Ticket #843: pipplayer.6.diff

File pipplayer.6.diff, 84.3 KB (added by skamithi, 13 years ago)

more bug fixes. toggleactivewindow and swappip should be fairly stable now. haven't tried all the different key actions to see what happens..added VideoOutput::IsResolutionSupported? . ran to check that main XV surface supports the specified resolution. also resolved some issues where pipplayer didn't die cleanly.

  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    204204      audio_samplerate(44100),      audio_stretchfactor(1.0f),
    205205      // Picture-in-Picture
    206206      pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false),
     207      ispip(false), softwareScalingPIP(false),
    207208      // Preview window support
    208209      argb_buf(NULL),               argb_size(0,0),
    209210      yuv2argb_conv(yuv2rgb_init_mmx(32, MODE_RGB)),
     
    294295
    295296    if (m_playbackinfo)
    296297    {
    297         m_playbackinfo->MarkAsInUse(false);
     298        if (!ispip)
     299            m_playbackinfo->MarkAsInUse(false);
    298300        delete m_playbackinfo;
    299301    }
    300302
     
    540542            return false;
    541543        }
    542544
     545        if (ispip)
     546        {
     547            if (m_tv)
     548                videoOutput->SetAsPIP(kPIPOnTV);
     549            else
     550                videoOutput->SetAsPIP(kPIPOn);
     551        }
     552
    543553        if (!videoOutput->Init(video_width, video_height, video_aspect,
    544554                               widget->winId(), 0, 0, widget->width(),
    545555                               widget->height(), 0))
    546556        {
    547557            errored = true;
     558        }
     559       
     560        if (errored && ispip)
     561        {
     562            softwareScalingPIP = true;
     563            delete videoOutput;
     564            videoOutput = NULL;
     565            errored = true;
    548566            return false;
    549567        }
    550568
     
    636654{
    637655    QString errMsg = QString::null;
    638656
    639     if ((audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
     657    if (ispip || (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
    640658    {
    641659        VERBOSE(VB_IMPORTANT, LOC +
    642660                QString("Disabling Audio, params(%1,%2,%3)")
     
    756774
    757775void NuppelVideoPlayer::AutoDeint(VideoFrame *frame)
    758776{
    759     if (!frame || m_scan_locked)
     777    if (!frame || m_scan_locked || ispip)
    760778        return;
    761779
    762780    if (frame->interlaced_frame)
     
    798816{
    799817    QMutexLocker locker(&videofiltersLock);
    800818
    801     if (!videoOutput || !videosync)
     819    if (!videoOutput || !videosync || ispip)
    802820        return; // hopefully this will be called again later...
    803821
    804822    m_scan_locked = (scan != kScan_Detect);
     
    10591077
    10601078void NuppelVideoPlayer::InitFilters(void)
    10611079{
     1080    if (ispip)
     1081        return;
     1082
    10621083    VideoFrameType itmp = FMT_YV12;
    10631084    VideoFrameType otmp = FMT_YV12;
    10641085    int btmp;
     
    25532574    else if (videoOutput)
    25542575    {
    25552576        // Set up deinterlacing in the video output method
    2556         m_double_framerate =
    2557             (videoOutput->SetupDeinterlace(true) &&
    2558              videoOutput->NeedsDoubleFramerate());
    2559 
     2577        if (ispip)
     2578        {
     2579            m_double_framerate = false;
     2580            videoOutput->SetupDeinterlace(true, "linearblend");
     2581        }
     2582        else
     2583        {
     2584            m_double_framerate =
     2585                (videoOutput->SetupDeinterlace(true) &&
     2586                videoOutput->NeedsDoubleFramerate());
     2587        }
     2588       
    25602589        videosync = VideoSync::BestMethod(
    25612590            videoOutput, fr_int, rf_int, m_double_framerate);
    25622591
     
    25892618        {
    25902619            pipplayer = setpipplayer;
    25912620            needsetpipplayer = false;
     2621            if (m_tv)
     2622                m_tv->PIPPlayerWake();
    25922623        }
    25932624
    25942625        if (ringBuffer->isDVD())
     
    30493080
    30503081    if (!InitVideo())
    30513082    {
    3052         qApp->lock();
    3053         DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
     3083        if (!ispip)
     3084        {
     3085            qApp->lock();
     3086            DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
    30543087                                   QObject::tr("Unable to initialize video."));
    3055         dialog->AddButton(QObject::tr("Return to menu."));
    3056         dialog->exec();
    3057         delete dialog;
     3088            dialog->AddButton(QObject::tr("Return to menu."));
     3089            dialog->exec();
     3090            delete dialog;
     3091            qApp->unlock();
     3092        }
    30583093
    3059         qApp->unlock();
    3060 
    30613094        if (audioOutput)
    30623095        {
    30633096            delete audioOutput;
     
    36563689    int numFrames = totalFrames;
    36573690
    36583691    if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE)
    3659         numFrames = (m_playbackinfo->endts.toTime_t() -
    3660                     m_playbackinfo->recstartts.toTime_t()) * video_frame_rate;
     3692        numFrames = (int)((m_playbackinfo->endts.toTime_t() -
     3693                    m_playbackinfo->recstartts.toTime_t()) * video_frame_rate);
    36613694
    36623695    int offset = (int) round(0.14 * (numFrames / video_frame_rate));
    36633696
     
    36803713
    36813714void NuppelVideoPlayer::SetBookmark(void)
    36823715{
    3683     if (!m_playbackinfo || !osd)
     3716    if (!m_playbackinfo)
    36843717        return;
    36853718
    36863719    m_playbackinfo->SetBookmark(framesPlayed);
    3687     osd->SetSettingsText(QObject::tr("Position Saved"), 1);
     3720    if (osd)
     3721    {
     3722        osd->SetSettingsText(QObject::tr("Position Saved"), 1);
    36883723
    3689     struct StatusPosInfo posInfo;
    3690     calcSliderPos(posInfo);
    3691     osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2);
     3724        struct StatusPosInfo posInfo;
     3725        calcSliderPos(posInfo);
     3726        osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2);
     3727    }
    36923728}
    36933729
    36943730void NuppelVideoPlayer::ClearBookmark(void)
  • libs/libmythtv/libmythtv.pro

     
    216216
    217217    # Video playback
    218218    HEADERS += tv_play.h                NuppelVideoPlayer.h
    219     HEADERS += DVDRingBuffer.h
     219    HEADERS += DVDRingBuffer.h          pipplayer.h
    220220    SOURCES += tv_play.cpp              NuppelVideoPlayer.cpp
    221     SOURCES += DVDRingBuffer.cpp
     221    SOURCES += DVDRingBuffer.cpp        pipplayer.cpp
    222222
    223223    # Text subtitle parser
    224224    HEADERS += textsubtitleparser.h     xine_demux_sputext.h
  • libs/libmythtv/tv_play.h

     
    3333class OSDListTreeType;
    3434class OSDGenericTree;
    3535class LiveTVChain;
     36class PIPPlayer;
    3637
    3738typedef QValueVector<QString>    str_vec_t;
    3839typedef QMap<QString,QString>    InfoMap;
     
    126127    void ShowNoRecorderDialog(void);
    127128    void FinishRecording(void);
    128129    void AskAllowRecording(const QStringList&, int, bool);
     130    void PIPPlayerWake(void) { pipplayerCond.wakeAll(); }
    129131    void PromptStopWatchingRecording(void);
    130132    void PromptDeleteRecording(QString title);
    131133   
    132 
    133134    // Boolean queries
    134135
    135136    /// Returns true if we are playing back a non-LiveTV recording.
     
    161162    bool IsErrored(void)         const { return errored; }
    162163    /// true if dialog is either videoplayexit, playexit or askdelete dialog
    163164    bool IsVideoExitDialog(void);
     165    /// true if PIP is active NVP
     166    bool IsPIPActiveNVP(void);
    164167   
    165168    // Other queries
    166169    int GetLastRecorderNum(void) const;
     
    320323
    321324    void SetupPlayer(bool isWatchingRecording);
    322325    void TeardownPlayer(void);
    323     void SetupPipPlayer(void);
    324     void TeardownPipPlayer(void);
    325326   
    326327    void HandleStateChange(void);
    327328    bool InStateChange(void) const;
     
    331332    void TogglePIPView(void);
    332333    void ToggleActiveWindow(void);
    333334    void SwapPIP(void);
     335    TVState GetPIPState(PIPPlayer *pip);
    334336    void SwapPIPSoon(void) { needToSwapPIP = true; }
    335 
     337   
    336338    void ToggleAutoExpire(void);
    337339
    338340    void BrowseStart(void);
     
    529531
    530532    // Video Players
    531533    NuppelVideoPlayer *nvp;
    532     NuppelVideoPlayer *pipnvp;
     534    PIPPlayer  *pipplayer;
    533535    NuppelVideoPlayer *activenvp;  ///< Player to which LiveTV events are sent
    534536
     537    //PIP Stuff
     538    QWaitCondition pipplayerCond;
     539
    535540    // Remote Encoders
    536541    /// Main recorder
    537542    RemoteEncoder *recorder;
    538     /// Picture-in-Picture recorder
    539     RemoteEncoder *piprecorder;
    540543    /// Recorder to which LiveTV events are being sent
    541544    RemoteEncoder *activerecorder;
    542545    /// Main recorder to use after a successful SwitchCards() call.
     
    546549
    547550    // LiveTVChain
    548551    LiveTVChain *tvchain;
    549     LiveTVChain *piptvchain;
    550552    QStringList tvchainUpdate;
    551553    QMutex tvchainUpdateLock;
    552554
    553555    // RingBuffers
    554556    RingBuffer *prbuffer;
    555     RingBuffer *piprbuffer;
    556557    RingBuffer *activerbuffer; ///< Ringbuffer to which LiveTV events are sent
    557558
    558559    // OSD info
     
    589590    pthread_t event;
    590591    /// Video decoder thread, runs nvp's NuppelVideoPlayer::StartPlaying().
    591592    pthread_t decode;
    592     /// Picture-in-Picture video decoder thread,
    593     /// runs pipnvp's NuppelVideoPlayer::StartPlaying().
    594     pthread_t pipdecode;
    595593
    596594    /// Condition to signal that the Event thread is up and running
    597595    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
     11class RingBuffer;
     12class ProgramInfo;
     13class LiveTVChain;
     14class RemoteEncoder;
     15class NuppelVideoPlayer;
     16
     17class 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
     86class RingBuffer;
     87class ProgramInfo;
     88class LiveTVChain;
     89class RemoteEncoder;
     90class NuppelVideoPlayer;
     91
     92class 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

     
    128128
    129129    // Sets
    130130    void SetParentWidget(QWidget *widget)     { parentWidget = widget; }
    131     void SetAsPIP(void)                       { SetNoAudio(); SetNullVideo(); }
     131    void SetAsPIP(bool setNullVideo)         
     132        { if (setNullVideo) SetNullVideo(); ispip = true; }
    132133    void SetNullVideo(void)                   { using_null_videoout = true; }
    133134    void SetFileName(QString lfilename)       { filename = lfilename; }
    134135    void SetExactSeeks(bool exact)            { exactseeks = exact; }
     
    140141    void SetVideoFilters(QString &filters)    { videoFilterList = filters; }
    141142    void SetFramesPlayed(long long played)    { framesPlayed = played; }
    142143    void SetEof(void)                         { eof = true; }
    143     void SetPipPlayer(NuppelVideoPlayer *pip)
     144    void SetPIPPlayer(NuppelVideoPlayer *pip)
    144145        { setpipplayer = pip; needsetpipplayer = true; }
    145146    void SetRecorder(RemoteEncoder *recorder);
    146147    void SetParentPlayer(TV *tv)             { m_tv = tv; }
     
    193194    bool    GetRawAudioState(void) const;
    194195    bool    GetLimitKeyRepeat(void) const     { return limitKeyRepeat; }
    195196    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); }
    197199    bool    IsErrored(void) const             { return errored; }
    198200    bool    IsPlaying(void) const             { return playing; }
    199201    bool    AtNormalSpeed(void) const         { return next_normal_speed; }
     
    203205    bool    PlayingSlowForPrebuffer(void) const { return m_playing_slower; }
    204206    bool    HasAudioIn(void) const            { return !no_audio_in; }
    205207    bool    HasAudioOut(void) const           { return !no_audio_out; }
     208    bool    PIPSoftwareScaling(void)          { return softwareScalingPIP; }
    206209
    207210    // Complicated gets
    208211    long long CalcMaxFFTime(long long ff, bool setjump = true) const;
     
    670673    NuppelVideoPlayer *pipplayer;
    671674    NuppelVideoPlayer *setpipplayer;
    672675    bool needsetpipplayer;
     676    bool ispip;
     677    bool softwareScalingPIP;
    673678
    674679    // Preview window support
    675680    unsigned char      *argb_buf;
  • libs/libmythtv/tv_play.cpp

     
    3939#include "DVDRingBuffer.h"
    4040#include "datadirect.h"
    4141#include "sourceutil.h"
     42#include "pipplayer.h"
    4243
    4344#ifndef HAVE_ROUND
    4445#define round(x) ((int) ((x) + 0.5))
     
    462463      lastProgram(NULL), jumpToProgram(false),
    463464      inPlaylist(false), underNetworkControl(false),
    464465      // Video Players
    465       nvp(NULL), pipnvp(NULL), activenvp(NULL),
     466      nvp(NULL), pipplayer(NULL), activenvp(NULL),
    466467      // Remote Encoders
    467       recorder(NULL), piprecorder(NULL), activerecorder(NULL),
     468      recorder(NULL), activerecorder(NULL),
    468469      switchToRec(NULL), lastrecordernum(-1),
    469470      // LiveTVChain
    470       tvchain(NULL), piptvchain(NULL),
     471      tvchain(NULL),
    471472      // RingBuffers
    472       prbuffer(NULL), piprbuffer(NULL), activerbuffer(NULL),
     473      prbuffer(NULL), activerbuffer(NULL),
    473474      // OSD info
    474475      dialogname(""), treeMenu(NULL), udpnotify(NULL), osdlock(true),
    475476      // LCD Info
     
    679680        delete tvchain;
    680681    }
    681682
    682     if (piptvchain)
    683     {
    684         VERBOSE(VB_IMPORTANT, LOC + "Deleting PiP TV Chain in destructor");
    685         piptvchain->DestroyChain();
    686         delete piptvchain;
    687     }   
    688 
    689683    if (ddMapLoaderRunning)
    690684    {
    691685        pthread_join(ddMapLoader, NULL);
     
    13791373            prbuffer->Pause();
    13801374            prbuffer->WaitForPause();
    13811375        }
    1382 
    1383         if (piprbuffer)
    1384         {
    1385             piprbuffer->StopReads();
    1386             piprbuffer->Pause();
    1387             piprbuffer->WaitForPause();
    1388         }
    13891376    }
    13901377
    13911378    if (stopPlayers)
     
    13931380        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (1/2)");
    13941381        if (nvp)
    13951382            nvp->StopPlaying();
    1396 
    1397         if (pipnvp)
    1398             pipnvp->StopPlaying();
    13991383    }
    14001384
    14011385    if (stopRecorders)
     
    14031387        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping recorder[s]");
    14041388        if (recorder)
    14051389            recorder->StopLiveTV();
    1406 
    1407         if (piprecorder)
    1408             piprecorder->StopLiveTV();
    14091390    }
    14101391
    14111392    if (stopPlayers)
     
    14131394        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (2/2)");
    14141395        if (nvp)
    14151396            TeardownPlayer();
    1416 
    1417         if (pipnvp)
    1418             TeardownPipPlayer();
     1397        if (pipplayer)
     1398        {
     1399            delete pipplayer;
     1400            pipplayer = NULL;
     1401        }
    14191402    }
    14201403    VERBOSE(VB_PLAYBACK, LOC + "StopStuff() -- end");
    14211404}
     
    14971480    return filters;
    14981481}
    14991482
    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 
    15221483void TV::TeardownPlayer(void)
    15231484{
    15241485    if (nvp)
     
    15681529        prbuffer = activerbuffer = NULL;
    15691530    }
    15701531
    1571     if (piprbuffer)
    1572     {
    1573         delete piprbuffer;
    1574         piprbuffer = NULL;
    1575     }
    1576 
    15771532    if (tvchain)
    15781533    {
    15791534        tvchain->DestroyChain();
     
    15821537    }
    15831538}
    15841539
    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 
    16241540void *TV::EventThread(void *param)
    16251541{
    16261542    TV *thetv = (TV *)param;
     
    16861602                        if (nvp->GetTVChain())
    16871603                            nvp->CheckTVChain();
    16881604                    }
    1689                     if (piptvchain && pipnvp && *it == piptvchain->GetID())
     1605                    if (pipplayer && pipplayer->IsLiveTV()
     1606                            && *it == pipplayer->GetLiveTVChain()->GetID())
    16901607                    {
     1608                        LiveTVChain *piptvchain = pipplayer->GetLiveTVChain();
    16911609                        piptvchain->ReloadAll();
    1692                         if (pipnvp->GetTVChain())
    1693                             pipnvp->CheckTVChain();
     1610                        if (pipplayer->GetNVP()->GetTVChain())
     1611                            pipplayer->GetNVP()->CheckTVChain();
    16941612                    }
    16951613                }
    16961614                tvchainUpdate.clear();
     
    17521670            wantsToQuit = true;
    17531671        }
    17541672
     1673        if (pipplayer && !pipplayer->IsPlaying())
     1674            TogglePIPView();
     1675
    17551676        if (StateIsPlaying(internalState))
    17561677        {
    17571678#ifdef USING_VALGRIND
     
    18591780            prevChan = tmp;
    18601781            pseudoLiveTVState[i] = kPseudoRecording;
    18611782
    1862             if (i && pipnvp)
     1783            if (i && pipplayer)
    18631784                TogglePIPView();
    18641785        }
    18651786
     
    18841805        if (++updatecheck >= 100)
    18851806        {
    18861807            OSDSet *oset;
    1887             if (GetOSD() && (oset = GetOSD()->GetSet("status")) &&
     1808            if (activenvp && GetOSD() &&
     1809                (oset = GetOSD()->GetSet("status")) &&
    18881810                oset->Displaying() && update_osd_pos &&
    18891811                (StateIsLiveTV(internalState) ||
    18901812                 StateIsPlaying(internalState)))
    18911813            {
    18921814                struct StatusPosInfo posInfo;
    1893                 nvp->calcSliderPos(posInfo);
     1815                activenvp->calcSliderPos(posInfo);
    18941816                GetOSD()->UpdateStatus(posInfo);
    18951817            }
    18961818
     
    19321854            if (activenvp)
    19331855            {
    19341856                struct StatusPosInfo posInfo;
    1935                 nvp->calcSliderPos(posInfo);
     1857                activenvp->calcSliderPos(posInfo);
    19361858                progress = (float)posInfo.position / 1000;
    19371859            }
    19381860            lcd->setChannelProgress(progress);
     
    19761898        {
    19771899            if (nvp)
    19781900                nvp->ExposeEvent();
     1901            if (pipplayer && pipplayer->GetNVP())
     1902                pipplayer->GetNVP()->ExposeEvent();
    19791903            return true;
    19801904        }
    19811905        case MythEvent::MythEventMessage:
     
    25582482            DoQueueTranscode("Low Quality");
    25592483        else if (action == "PLAY")
    25602484            DoPlay();
     2485        else if (action == "TOGGLEPIPMODE")
     2486            TogglePIPView();
     2487        else if (action == "TOGGLEPIPWINDOW")
     2488            ToggleActiveWindow();
     2489        else if (action == "SWAPPIP")
     2490            SwapPIPSoon();
    25612491        else if (action == "PAUSE")
    25622492            DoPause();
    25632493        else if (action == "SPEEDINC" && !activerbuffer->InDVDMenuOrStillFrame())
     
    29262856                SwitchCards();
    29272857            else if (action == "GUIDE")
    29282858                EditSchedule(kScheduleProgramGuide);
    2929             else if (action == "TOGGLEPIPMODE")
    2930                 TogglePIPView();
    2931             else if (action == "TOGGLEPIPWINDOW")
    2932                 ToggleActiveWindow();
    2933             else if (action == "SWAPPIP")
    2934                 SwapPIPSoon();
    29352859            else if (action == "TOGGLEBROWSE")
    29362860                BrowseStart();
    29372861            else if (action == "PREVCHAN")
     
    32133137    }
    32143138}
    32153139
     3140bool TV::IsPIPActiveNVP(void)
     3141{
     3142    if (pipplayer && pipplayer->GetNVP())
     3143        return (pipplayer->GetNVP() == activenvp);
     3144    return false;
     3145}
     3146
    32163147void TV::TogglePIPView(void)
    32173148{
    3218     if (!pipnvp)
     3149    if (!pipplayer)
    32193150    {
    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())
    32233159        {
    3224             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP failed to locate recorder");
    3225             if (testrec)
    3226                 delete testrec;
     3160            pipplayer->Show();
    32273161            return;
    32283162        }
    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         }
    32453163        else
    32463164        {
    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()))
    32623169            {
    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);
     3176                    if (pipplayer->IsPlaying())
     3177                    {
     3178                        activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3179                        pipplayerCond.wait();
     3180                        return;
     3181                    }
     3182                }
    32653183            }
    3266             VERBOSE(VB_PLAYBACK, "PiP NVP Started");
    3267 
    3268             if (pipnvp->IsDecoderThreadAlive())
    3269                 nvp->SetPipPlayer(pipnvp);
    3270             else
    3271             {
    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             }
    32793184        }
    3280         else
    3281         {
    3282             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start");
    3283             TeardownPipPlayer();
    3284         }
    32853185    }
    3286     else
     3186   
     3187    if (IsPIPActiveNVP())
     3188        ToggleActiveWindow();
     3189
     3190    if (nvp->HasPIPPlayer())
    32873191    {
    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);
     3192        activenvp->SetPIPPlayer(NULL);
     3193        pipplayerCond.wait();
    33073194    }
     3195   
     3196    delete pipplayer;
     3197    pipplayer = NULL;
    33083198}
    33093199
    33103200void TV::ToggleActiveWindow(void)
    33113201{
    3312     if (!pipnvp)
     3202    // toggleactivewindow works only if the main window is live tv.
     3203    // problem is playbackinfo and internalstate management.
     3204    if (!pipplayer  || !pipplayer->GetNVP() ||
     3205        (!IsPIPActiveNVP() && StateIsPlaying(internalState)))
     3206    {
    33133207        return;
    3314 
     3208    }
     3209   
    33153210    lockTimerOn = false;
    3316     if (activenvp == nvp)
     3211    LiveTVChain *piptvchain = NULL;
     3212 
     3213    if (!IsPIPActiveNVP())
    33173214    {
    3318         activenvp = pipnvp;
    3319         activerbuffer = piprbuffer;
    3320         activerecorder = piprecorder;
     3215       
     3216        activenvp      = pipplayer->GetNVP();
     3217        activerbuffer  = pipplayer->GetRingBuffer();
     3218        activerecorder = pipplayer->GetRecorder();
     3219        piptvchain     = pipplayer->GetLiveTVChain();
     3220        internalState  = GetPIPState(pipplayer);
     3221        if (pipplayer->GetProgramInfo() && !pipplayer->IsLiveTV())
     3222            SetCurrentlyPlaying(pipplayer->GetProgramInfo());
    33213223    }
    33223224    else
    33233225    {
    3324         activenvp = nvp;
    3325         activerbuffer = prbuffer;
     3226        activenvp      = nvp;
     3227        activerbuffer  = prbuffer;
    33263228        activerecorder = recorder;
     3229        internalState  = kState_WatchingLiveTV;
    33273230    }
    3328     LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    3329     ProgramInfo *pginfo = chain->GetProgramAt(-1);
    3330     if (pginfo)
    3331     {
    3332         SetCurrentlyPlaying(pginfo);
    3333         delete pginfo;
    3334     }
     3231
     3232   if (activerecorder)
     3233   {
     3234        LiveTVChain *chain  = (activenvp == nvp) ? tvchain : piptvchain;
     3235        ProgramInfo *pginfo = chain->GetProgramAt(-1);
     3236        if (pginfo)
     3237        {
     3238            SetCurrentlyPlaying(pginfo);
     3239            delete pginfo;
     3240        }
     3241   }
    33353242}
    33363243
     3244
    33373245struct pip_info
    33383246{
    33393247    RingBuffer    *buffer;
    33403248    RemoteEncoder *recorder;
    33413249    LiveTVChain   *chain;
    33423250    long long      frame;
     3251    ProgramInfo   *pginfo;
    33433252};
    33443253
    33453254void TV::SwapPIP(void)
    33463255{
    3347     if (!pipnvp || !piptvchain || !tvchain)
     3256    if (!pipplayer)
     3257        // TODO print something on OSD informing use that PIP swap cannot be done
    33483258        return;
    33493259
    3350     lockTimerOn = false;
     3260    bool use_nullvideo = pipplayer->UsingNullVideo();
     3261    bool pipislivetv = StateIsLiveTV(internalState);
     3262   
     3263    if (activenvp != nvp)
     3264        ToggleActiveWindow();
    33513265
     3266    if (paused)
     3267        DoPause();
     3268    StopFFRew();
     3269    NormalSpeed();
     3270
     3271   if (playbackinfo)
     3272       playbackinfo->setIgnoreBookmark(false);
     3273   if (pipplayer->GetProgramInfo())
     3274       pipplayer->GetProgramInfo()->setIgnoreBookmark(false);
     3275   
     3276   // set the bookmark
     3277    activenvp->SetBookmark();
     3278    pipplayer->GetNVP()->SetBookmark();
     3279   
    33523280    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 
     3281    main.buffer      = prbuffer;
     3282    main.recorder    = recorder;
     3283    main.chain       = tvchain;
     3284    main.frame       = nvp->GetFramesPlayed();
     3285    if (StateIsPlaying(internalState))
     3286        main.pginfo = new ProgramInfo(*playbackinfo);
     3287    else
     3288        main.pginfo = NULL;
     3289   
     3290    pip.buffer       = pipplayer->GetRingBuffer();
     3291    pip.recorder     = pipplayer->GetRecorder();
     3292    pip.chain        = pipplayer->GetLiveTVChain();
     3293    pip.frame        = pipplayer->GetNVP()->GetFramesPlayed();
     3294    if (!pipplayer->IsLiveTV())
     3295        pip.pginfo   = new ProgramInfo(*pipplayer->GetProgramInfo());
     3296    else
     3297        pip.pginfo   = NULL;
     3298 
     3299    pipplayer->Hide();
     3300    if (use_nullvideo)
     3301    {
     3302        activenvp->SetPIPPlayer(NULL);
     3303        pipplayerCond.wait();
     3304    }
     3305    pipplayer->SetReinit(false);
     3306    pipplayer->StopPlaying();
     3307   
    33623308    prbuffer->Pause();
    33633309    prbuffer->WaitForPause();
    33643310
    3365     piprbuffer->Pause();
    3366     piprbuffer->WaitForPause();
     3311    nvp->StopPlaying();
    33673312
    3368     nvp->StopPlaying();
    3369     pipnvp->StopPlaying();
    33703313    {
    3371         QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd...
     3314        QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd..
    33723315        pthread_join(decode, NULL);
    33733316        delete nvp;
    33743317        nvp = NULL;
    3375         pthread_join(pipdecode, NULL);
    3376         delete pipnvp;
    3377         pipnvp = NULL;
    33783318    }
    33793319
     3320    if (playbackinfo)
     3321        delete playbackinfo;
     3322   
    33803323    activerbuffer  = prbuffer = pip.buffer;
    33813324    activerecorder = recorder = pip.recorder;
    33823325    tvchain                   = pip.chain;
     3326    playbackinfo              = pip.pginfo;
     3327    internalState             = GetPIPState(pipplayer);
    33833328
    3384     piprbuffer  = main.buffer;
    3385     piprecorder = main.recorder;
    3386     piptvchain  = main.chain;
    3387 
     3329    pipplayer->SetRingBuffer(main.buffer);
     3330    pipplayer->SetRecorder(main.recorder);
     3331    pipplayer->SetLiveTVChain(main.chain);
     3332    pipplayer->SetProgramInfo(main.pginfo);
     3333   
     3334    VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1")
     3335            .arg(StateToString(internalState)));
     3336   
    33883337    prbuffer->Seek(0, SEEK_SET);
    33893338    prbuffer->Unpause();
    3390     StartPlayer(false);
     3339
     3340    if (internalState == kState_WatchingRecording)
     3341        StartPlayer(true);
     3342    else
     3343        StartPlayer(false);
     3344
    33913345    activenvp = nvp;
    3392     nvp->FastForward(pip.frame/recorder->GetFrameRate());
    3393 
    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())
     3346    usleep(10000);
     3347    if (tvchain)
     3348        nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3349   
     3350    pipplayer->GetRingBuffer()->Seek(0, SEEK_SET);
     3351    pipplayer->GetRingBuffer()->Unpause();
     3352 
     3353    if (use_nullvideo)
    34003354    {
    3401         piptvchain->ReloadAll();
    3402         usleep(5000);
     3355        pipplayer->StartPlaying(main.pginfo, pipislivetv, true);
     3356        if (pipplayer->IsPlaying())
     3357            activenvp->SetPIPPlayer(pipplayer->GetNVP());
    34033358    }
    3404     VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");
    3405     pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());
     3359    else
     3360        pipplayer->StartPlaying(main.pginfo, pipislivetv);
    34063361
    3407     if (pipnvp->IsDecoderThreadAlive())
    3408         nvp->SetPipPlayer(pipnvp);
    3409     else
     3362    if (pipplayer->IsPlaying())
    34103363    {
    3411         VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start");
    3412         TeardownPipPlayer();
     3364        if (!use_nullvideo)
     3365            pipplayer->Show();
     3366        if (pipplayer->GetLiveTVChain())
     3367        {
     3368            pipplayer->GetLiveTVChain()->ReloadAll();
     3369            usleep(5000);
     3370        }
    34133371    }
    34143372
    3415     ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
    3416     if (pginfo)
     3373    if (internalState == kState_WatchingLiveTV)
     3374        SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV);
     3375
     3376    if (pipplayer->IsLiveTV())
     3377        SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3378
     3379    if (pipplayer->GetLiveTVChain())
     3380        pipplayer->GetNVP()->FastForward(main.frame/pipplayer->GetRecorder()->GetFrameRate());
     3381
     3382    if (tvchain)
    34173383    {
    3418         SetCurrentlyPlaying(pginfo);
    3419         delete pginfo;
     3384        ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
     3385        if (pginfo)
     3386        {
     3387            SetCurrentlyPlaying(pginfo);
     3388            delete pginfo;
     3389        }
    34203390    }
     3391    pipplayer->SetReinit(true);
    34213392}
    34223393
     3394TVState TV::GetPIPState(PIPPlayer *player)
     3395{
     3396    if (player->IsLiveTV())
     3397        return kState_WatchingLiveTV;
     3398    else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0))
     3399        return kState_WatchingRecording;
     3400    else
     3401        return kState_WatchingPreRecorded;
     3402}
     3403
    34233404void TV::DoPlay(void)
    34243405{
    34253406    float time = 0.0;
     
    34703451    if (activerbuffer->InDVDMenuOrStillFrame())
    34713452        return;
    34723453
     3454    if (IsPIPActiveNVP())
     3455    {
     3456        if (pipplayer->IsPaused())
     3457            pipplayer->Play();
     3458        else
     3459            pipplayer->Pause();
     3460        return;
     3461    }
     3462   
    34733463    speed_index = 0;
    34743464    float time = 0.0;
    34753465
    34763466    if (paused)
     3467    {
    34773468        activenvp->Play(normal_speed, true);
     3469        if (pipplayer)
     3470            pipplayer->Play(normal_speed);
     3471    }
    34783472    else
    34793473    {
    34803474        if (doing_ff_rew)
     
    34853479        }
    34863480       
    34873481        activenvp->Pause();
     3482        if (pipplayer)
     3483            pipplayer->Pause();
    34883484    }
    34893485
    34903486    paused = !paused;
     
    38493845
    38503846    RemoteEncoder *testrec = NULL;
    38513847
    3852     if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
     3848    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer)
    38533849        return;
    38543850
    38553851    if (/*chanid || */!channum.isEmpty())
     
    45294525    if (showStatus)
    45304526    {
    45314527        osd->HideAll();
    4532         if (nvp)
     4528        if (activenvp)
    45334529        {
    45344530            struct StatusPosInfo posInfo;
    4535             nvp->calcSliderPos(posInfo);
     4531            activenvp->calcSliderPos(posInfo);
    45364532            osd->ShowStatus(posInfo, false, tr("Position"),
    45374533                              osd_prog_info_timeout);
    45384534            update_osd_pos = true;
     
    53695365                menurunning = false;
    53705366                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    53715367            }
    5372             else if (piprecorder &&
    5373                      cardnum == piprecorder->GetRecorderNumber())
     5368            else if (pipplayer && pipplayer->GetRecorder() &&
     5369                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53745370            {
    53755371                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
    53765372                TogglePIPView();
     
    53885384                wantsToQuit = false;
    53895385                exitPlayer = true;
    53905386            }
    5391             else if (piprecorder &&
    5392                      cardnum == piprecorder->GetRecorderNumber())
     5387            else if (pipplayer && pipplayer->GetRecorder() &&
     5388                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53935389            {
    53945390                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
    53955391                TogglePIPView();
     
    54055401            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
    54065402
    54075403            if ((recorder    && cardnum == recorder->GetRecorderNumber()) ||
    5408                 (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     5404                (pipplayer && pipplayer->GetRecorder() &&
     5405                 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()))
    54095406            {
    54105407                if (watch)
    54115408                {
     
    54145411                    if (pi.FromStringList(list, 0))
    54155412                        SetPseudoLiveTV(s, &pi, kPseudoChangeChannel);
    54165413
    5417                     if (!s && pipnvp)
     5414                    if (!s && pipplayer)
    54185415                        TogglePIPView();
    54195416                }
    54205417                else
     
    64086405
    64096406void TV::ShowOSDTreeMenu(void)
    64106407{
     6408    if (IsPIPActiveNVP())
     6409        return;
     6410
    64116411    BuildOSDTreeMenu();
    64126412
    64136413    if (GetOSD())
     
    64366436
    64376437    if (StateIsLiveTV(GetState()))
    64386438    {
    6439         bool freeRecorders = (pipnvp != NULL);
     6439        bool freeRecorders = (pipplayer != NULL);
    64406440        if (!freeRecorders)
    64416441            freeRecorders = RemoteGetFreeRecorderCount();
    64426442
     
    70767076{
    70777077    VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()");
    70787078
     7079    LiveTVChain *piptvchain = NULL;
     7080    if (pipplayer)
     7081        piptvchain = pipplayer->GetLiveTVChain();
     7082
    70797083    LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    70807084
    70817085    if (activenvp && chain)
  • libs/libmythtv/videooutbase.cpp

     
    171171    pip_desired_display_size(160,128),  pip_display_size(0,0),
    172172    pip_video_size(0,0),
    173173    pip_tmp_buf(NULL),                  pip_scaling_context(NULL),
     174    piptype(kPIPOff),
    174175
    175176    // Video resizing (for ITV)
    176177    vsz_enabled(false),
     
    253254
    254255    db_vdisp_profile->SetInput(video_dim);
    255256
    256     letterbox  = db_letterbox;
     257    if (piptype == kPIPOff)
     258        letterbox  = db_letterbox;
    257259
    258260    VideoAspectRatioChanged(aspect); // apply aspect ratio and letterbox mode
    259261
     
    525527    visible = GetVisibleOSDBounds(visible_aspect, font_scaling);
    526528}
    527529
     530bool VideoOutput::IsResolutionSupported(int width, int height)
     531{
     532    (void)width;
     533    (void)height;
     534    return true;
     535}
     536
    528537static float sq(float a) { return a*a; }
    529538//static float lerp(float r, float a, float b)
    530539//    { return ((1.0f - r) * a) + (r * b); }
     
    10441053
    10451054    db_pict_attr[attributeType] = newValue;
    10461055}
     1056/*
     1057 * \brief Determines PIP Window size and Position.
     1058 */
     1059QRect 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);
    10471098
     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
    10481144/**
    10491145 * \fn VideoOutput::DoPipResize(int,int)
    10501146 * \brief Sets up Picture in Picture image resampler.
     
    11111207    int pipw, piph;
    11121208
    11131209    VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
     1210
    11141211    float pipVideoAspect = pipplayer->GetVideoAspect();
    1115     uint  pipVideoWidth  = pipplayer->GetVideoWidth();
    1116     uint  pipVideoHeight = pipplayer->GetVideoHeight();
    11171212
    11181213    // If PiP is not initialized to values we like, silently ignore the frame.
    11191214    if ((video_aspect <= 0) || (pipVideoAspect <= 0) ||
     
    11231218        pipplayer->ReleaseCurrentFrame(pipimage);
    11241219        return;
    11251220    }
     1221   
     1222    QRect piprect = GetPIPRect(db_pip_location, pipplayer);
    11261223
    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   
    11601228    // Scale the image if we have to...
    11611229    unsigned char *pipbuf = pipimage->buf;
    11621230    if (pipw != pip_desired_display_size.width() ||
     
    11861254
    11871255
    11881256    // 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();
    12111259
    12121260    // Copy Y (intensity values)
    12131261    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
     8static void *SpawnPIPVideoThread(void *param)
     9{   
     10    NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)param;
     11    nvp->StartPlaying();
     12    nvp->StopPlaying();
     13    return NULL;
     14}
     15 
     16PIPPlayer::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
     27PIPPlayer::~PIPPlayer(void)
     28{
     29    StopPlaying();
     30    if (pipWindow)
     31        pipWindow->deleteLater();
     32};
     33
     34PIPPlayer * 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
     47PIPPlayer * PIPPlayer::Create(const QRect &rect)
     48{
     49    PIPPlayer *tmppip = new PIPPlayer();
     50    tmppip->Init(rect, "pip player");
     51    return tmppip;
     52}
     53
     54void 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
     67void 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 */
     99bool 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
     225void 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 */
     261void 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 */
     270void 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 */
     279void PIPPlayer::SetRecorder(RemoteEncoder  *recorder)
     280{
     281    if (!IsPlaying())
     282        piprecorder = recorder;
     283}
     284
     285void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo)
     286{
     287    if (!IsPlaying())
     288    {
     289        if (piprecinfo)
     290            delete piprecinfo;
     291        piprecinfo = pginfo;
     292    }
     293}
     294
     295bool 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
     306bool 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
     321void PIPPlayer::Hide(void)
     322{
     323    if (pipWindow && pipWindow->isVisible())
     324        pipWindow->hide();
     325}
     326
     327void PIPPlayer::Show(void)
     328{   
     329    if (pipWindow && pipWindow->isHidden())
     330        pipWindow->show();
     331}
     332
     333bool PIPPlayer::IsHidden(void)
     334{
     335    if (pipWindow && pipWindow->isHidden())
     336        return true;
     337    return false;
     338}
     339
     340void 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
     356void PIPPlayer::Pause(void)
     357{
     358    if (IsPlaying() && !paused)
     359    {
     360        pipnvp->Pause();
     361        paused = true;
     362    }
     363}
     364
     365void 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

     
    8888        { return XVideoIDCT <= VideoOutputSubType(); }
    8989    virtual bool hasVLDAcceleration(void) const
    9090        { return XVideoVLD == VideoOutputSubType(); }
     91    virtual bool hasXVAcceleration(void) const
     92        { return VideoOutputSubType() == XVideo; }
    9193
    9294    void CheckFrameStates(void);
     95    bool IsResolutionSupported(int width, int height);
    9396
    9497    static MythCodecID GetBestSupportedCodec(uint width, uint height,
    9598                                             uint osd_width, uint osd_height,
  • libs/libmythtv/videoout_xv.cpp

     
    12181218        db_vdisp_profile->SetVideoRenderer(renderer);
    12191219    }
    12201220
     1221    const QString osdrenderer = db_vdisp_profile->GetOSDRenderer();
     1222    if (piptype == kPIPOnTV  &&
     1223            (osdrenderer != "opengl" || osdrenderer != "composite"))
     1224    {
     1225        VERBOSE(VB_IMPORTANT, LOC + QString("XV PIP not supported with blended OSD. "
     1226                    "Using software scaled PIP."));
     1227        return false;
     1228    }
    12211229    // Initialize the OSD, if we need to
    1222     InitOSD(db_vdisp_profile->GetOSDRenderer());
     1230    if (piptype == kPIPOff)
     1231        InitOSD(osdrenderer);
    12231232
    12241233    // Create video buffers
    12251234    bool use_xv  = (renderer.left(2) == "xv");
     
    12591268{
    12601269    needrepaint = true;
    12611270
     1271    // for PIP use software scaled image if width or height <= 64
     1272    if (piptype > kPIPOff &&
     1273        (width <= 64 || height <= 64))
     1274        return false;
     1275       
    12621276    XV_INIT_FATAL_ERROR_TEST(winid <= 0, "Invalid Window ID.");
    12631277
    12641278    XJ_disp = MythXOpenDisplay();
     
    32673281#endif // USING_XVMC
    32683282}
    32693283
     3284bool VideoOutputXv::IsResolutionSupported(int width, int height)
     3285{
     3286    if (width == 0 || height == 0)
     3287        return false;
     3288
     3289    if (xv_port >= 0 && xv_chroma)
     3290    {
     3291        int size = 0;
     3292        int desiredsize = 0;
     3293        XvImage *img = NULL;
     3294        XShmSegmentInfo *info = new XShmSegmentInfo;
     3295        X11S(img = XvShmCreateImage(XJ_disp, xv_port, xv_chroma, 0,
     3296                width, height, info));
     3297        size = img->data_size + 64;
     3298        desiredsize =  width * height * 3 / 2;
     3299        if (img && size < desiredsize)
     3300        {
     3301            VERBOSE(VB_IMPORTANT, LOC_ERR + QString("IsResolutionSupported(): "
     3302                    "WxH %1x%2 not supported on this Xv Surface")
     3303                    .arg(width).arg(height));
     3304            XFree(img);
     3305            delete info;
     3306            return false;
     3307        }
     3308
     3309        return true;
     3310    }
     3311    return false;
     3312}
     3313       
    32703314bool VideoOutputXv::IsDisplaying(VideoFrame* frame)
    32713315{
    32723316    (void)frame;
  • libs/libmythtv/videooutbase.h

     
    7979    kPIPBottomRight
    8080};
    8181
     82enum PIPType
     83{
     84    kPIPOff = 0,
     85    kPIPOn, // PIP but not for TV
     86    kPIPOnTV // PIP used in TV mode
     87};
     88
    8289enum ZoomDirections
    8390{
    8491    kZoomHome = 0,
     
    190197    virtual void GetOSDBounds(QRect &visible, QRect &total,
    191198                              float &pixelAspect, float &fontScale) const;
    192199
     200    virtual bool IsResolutionSupported(int width, int height);
     201
    193202    /// \brief Returns current display's frame refresh period in microseconds.
    194203    ///        e.g. 1000000 / frame_rate_in_Hz
    195204    virtual int GetRefreshRate(void) = 0;
     
    225234    bool AllowPreviewEPG(void) { return allowpreviewepg; }
    226235
    227236    /// \brief Returns true iff Motion Compensation acceleration is available.
    228     virtual bool hasMCAcceleration() const { return false; }
     237    virtual bool hasMCAcceleration(void) const { return false; }
    229238    /// \brief Returns true iff Inverse Discrete Cosine Transform acceleration
    230239    ///        is available.
    231     virtual bool hasIDCTAcceleration() const { return false; }
     240    virtual bool hasIDCTAcceleration(void) const { return false; }
    232241    /// \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; }
    234245
    235246    /// \brief Sets the number of frames played
    236247    virtual void SetFramesPlayed(long long fp) { framesPlayed = fp; };
     
    308319    /// \brief Tells the player to resize the video frame (used for ITV)
    309320    void SetVideoResize(const QRect &videoRect);
    310321
     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
    311329  protected:
    312330    void InitBuffers(int numdecode, bool extra_for_pause, int need_free,
    313331                     int needprebuffer_normal, int needprebuffer_small,
     
    384402    QSize   pip_video_size;
    385403    unsigned char      *pip_tmp_buf;
    386404    ImgReSampleContext *pip_scaling_context;
     405    PIPType    piptype;
    387406
    388407    // Video resizing (for ITV)
    389408    bool    vsz_enabled;
  • programs/mythfrontend/playbackbox.cpp

     
    3838#include "remoteutil.h"
    3939#include "lcddevice.h"
    4040#include "previewgenerator.h"
     41#include "pipplayer.h"
    4142#include "playgroup.h"
    4243#include "customedit.h"
    4344
     
    262263      // Volatile drawing variables
    263264      paintSkipCount(0),                paintSkipUpdate(false),
    264265      // Preview Video Variables
    265       previewVideoNVP(NULL),            previewVideoRingBuf(NULL),
    266       previewVideoRefreshTimer(new QTimer(this)),
    267       previewVideoBrokenRecId(0),       previewVideoState(kStopped),
    268       previewVideoStartTimerOn(false),  previewVideoEnabled(false),
    269       previewVideoPlaying(false),       previewVideoThreadRunning(false),
    270       previewVideoKillState(kDone),
     266      previewPlayer(NULL), previewVideoStartTimer(new QTimer(this)),
     267      previewVideoRefreshTimer(new QTimer(this)),
     268      previewVideoEnabled(false),
     269      previewTimeout(2000), software_scaled(false),
    271270      // Preview Image Variables
    272271      previewPixmapEnabled(false),      previewPixmap(NULL),
    273272      previewSuspend(false),            previewChanid(""),
     
    369368    connected = FillList();
    370369
    371370    // connect up timers...
    372     connect(previewVideoRefreshTimer, SIGNAL(timeout()),
     371    connect(previewVideoStartTimer,        SIGNAL(timeout()),
    373372            this,                     SLOT(timeout()));
     373    connect(previewVideoRefreshTimer,       SIGNAL(timeout()),
     374            this,                     SLOT(refreshVideo()));
    374375    connect(freeSpaceTimer,           SIGNAL(timeout()),
    375376            this,                     SLOT(setUpdateFreeSpace()));
    376377    connect(fillListTimer,            SIGNAL(timeout()),
    377378            this,                     SLOT(listChanged()));
    378379
    379380    // preview video & preview pixmap init
    380     previewVideoRefreshTimer->start(500);
    381381    previewStartts = QDateTime::currentDateTime();
    382 
     382    previewVideoStartTimer->start(previewTimeout);
     383    previewVideoRefreshTimer->start(50);
    383384    // misc setup
    384385    updateBackground();
    385386    setNoErase();
     
    398399    gContext->removeListener(this);
    399400    gContext->removeCurrentLocation();
    400401
    401     if (!m_player)
    402         killPlayerSafe();
     402    killPlayer();
     403   
     404    if (previewVideoStartTimer)
     405    {
     406        previewVideoStartTimer->disconnect(this);
     407        previewVideoStartTimer->deleteLater();
     408        previewVideoStartTimer = NULL;
     409    }
    403410
    404411    if (previewVideoRefreshTimer)
    405412    {
     
    464471        delete previewPixmap;
    465472        previewPixmap = NULL;
    466473    }
    467 }
    468474
    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 need
    486            to allow updateVideo() to run to handle changes in
    487            previewVideoStates */
    488         qApp->unlock();
    489         qApp->processEvents();
    490         usleep(500);
    491         qApp->lock();
    492     }
    493     previewVideoState = kStopped;
    494 
    495     ignoreKeyPressEvents = false;
    496475}
    497476
    498477void PlaybackBox::LoadWindow(QDomElement &element)
     
    523502            }
    524503        }
    525504    }
     505
     506    if (previewVideoEnabled)
     507    {
     508        previewPlayer = PIPPlayer::Create(drawVideoBounds);
     509        if (previewPlayer)
     510            previewPlayer->Hide();
     511        previewPixmapEnabled = true;
     512    }
    526513}
    527514
    528515void PlaybackBox::parseContainer(QDomElement &element)
     
    596583
    597584void PlaybackBox::exitWin()
    598585{
     586    killPlayer();
    599587    if (m_player)
    600588    {
    601589        if (curitem)
     
    603591        curitem = NULL;
    604592        pbbIsVisibleCond.wakeAll();
    605593    }
    606     else
    607         killPlayerSafe();
    608 
    609594    accept();
    610595}
    611596
     
    785770    QMap<QString, QString> infoMap;
    786771    QPainter tmp(&pix);
    787772       
    788     if (previewVideoPlaying)
    789         previewVideoState = kChanging;
    790773
    791774    LayerSet *container = NULL;
    792775    if (type != Delete)
     
    799782        if (curitem)
    800783            curitem->ToMap(infoMap);
    801784       
    802         if ((previewVideoEnabled == 0) &&
    803             (previewPixmapEnabled == 0))
     785        if (previewPixmapEnabled == 0)
    804786            container->UseAlternateArea(true);
    805787
    806788        container->ClearAllText();
     
    845827    tmp.end();
    846828    p->drawPixmap(pr.topLeft(), pix);
    847829
    848     previewVideoStartTimer.start();
    849     previewVideoStartTimerOn = true;
    850830}
    851831
    852832void PlaybackBox::updateInfo(QPainter *p)
     
    883863    // If we're displaying group info don't update the video.
    884864    if (inTitle && haveGroupInfoSet)
    885865        return;
    886 
     866   
    887867    /* show a still frame if the user doesn't want a video preview or nvp
    888868     * hasn't started playing the video preview yet */
    889     if (curitem && !playingSomething &&
    890         (!previewVideoEnabled             ||
    891          !previewVideoPlaying             ||
    892          (previewVideoState == kStarting) ||
    893          (previewVideoState == kChanging)))
     869    if ((curitem && previewPixmapEnabled && !previewPlayer) ||
     870         (curitem && previewPlayer && previewPlayer->IsHidden()))
    894871    {
    895872        QPixmap temp = getPixmap(curitem);
    896873        if (temp.width() > 0)
    897874            p->drawPixmap(drawVideoBounds.x(), drawVideoBounds.y(), temp);
    898875    }
    899 
    900     /* keep calling killPlayer() to handle nvp cleanup */
    901     /* until killPlayer() is done */
    902     if (previewVideoKillState != kDone && !killPlayer())
    903         return;
    904 
    905     /* if we aren't supposed to have a preview playing then always go */
    906     /* to the stopping previewVideoState */
    907     if (!previewVideoEnabled &&
    908         (previewVideoState != kKilling) && (previewVideoState != kKilled))
     876   
     877    if (curitem && previewVideoEnabled && previewPlayer &&
     878            !previewPlayer->IsHidden())
    909879    {
    910         previewVideoState = kStopping;
    911     }
    912 
    913     /* if we have no nvp and aren't playing yet */
    914     /* if we have an item we should start playing */
    915     if (!previewVideoNVP   && previewVideoEnabled  &&
    916         curitem            && !previewVideoPlaying &&
    917         (previewVideoState != kKilling) &&
    918         (previewVideoState != kKilled)  &&
    919         (previewVideoState != kStarting))
    920     {
    921         ProgramInfo *rec = curitem;
    922 
    923         if (fileExists(rec) == false)
    924         {
    925             VERBOSE(VB_IMPORTANT, QString("Error: File '%1' missing.")
    926                     .arg(rec->pathname));
    927 
    928             previewVideoState = kStopping;
    929 
    930             ProgramInfo *tmpItem = findMatchingProg(rec);
    931             if (tmpItem)
    932                 tmpItem->availableStatus = asFileNotFound;
    933 
    934             return;
    935         }
    936         previewVideoState = kStarting;
    937     }
    938 
    939     if (previewVideoState == kChanging)
    940     {
    941         if (previewVideoNVP)
    942         {
    943             killPlayer(); /* start killing the player */
    944             return;
    945         }
    946 
    947         previewVideoState = kStarting;
    948     }
    949 
    950     if ((previewVideoState == kStarting) &&
    951         (!previewVideoStartTimerOn ||
    952          (previewVideoStartTimer.elapsed() > 500)))
    953     {
    954         previewVideoStartTimerOn = false;
    955 
    956         if (!previewVideoNVP)
    957             startPlayer(curitem);
    958 
    959         if (previewVideoNVP)
    960         {
    961             if (previewVideoNVP->IsPlaying())
    962                 previewVideoState = kPlaying;
    963         }
     880        if (!previewPlayer->IsSameProgram(curitem))
     881            stopPlayer();
    964882        else
    965         {
    966             // already dead, so clean up
    967             killPlayer();
    968             return;
    969         }
     883            previewPlayer->GetNVP()->ExposeEvent();
    970884    }
    971 
    972     if ((previewVideoState == kStopping) || (previewVideoState == kKilling))
    973     {
    974         if (previewVideoNVP)
    975         {
    976             killPlayer(); /* start killing the player and exit */
    977             return;
    978         }
    979 
    980         if (previewVideoState == kKilling)
    981             previewVideoState = kKilled;
    982         else
    983             previewVideoState = kStopped;
    984     }
    985 
    986     /* if we are playing and nvp is running, then grab a new video frame */
    987     if ((previewVideoState == kPlaying) && previewVideoNVP->IsPlaying() &&
    988         !playingSomething)
    989     {
    990         QSize size = drawVideoBounds.size();
    991         float saspect = ((float)size.width()) / ((float)size.height());
    992         float vaspect = previewVideoNVP->GetVideoAspect();
    993         size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
    994         size.setHeight(((size.height() + 7) / 8) * 8);
    995         size.setWidth( ((size.width()  + 7) / 8) * 8);
    996         const QImage &img = previewVideoNVP->GetARGBFrame(size);
    997         p->drawImage(drawVideoBounds.x(), drawVideoBounds.y(), img);
    998     }
    999 
    1000     /* have we timed out waiting for nvp to start? */
    1001     if ((previewVideoState == kPlaying) && !previewVideoNVP->IsPlaying())
    1002     {
    1003         if (previewVideoPlayingTimer.elapsed() > 2000)
    1004         {
    1005             previewVideoState = kStarting;
    1006             killPlayer();
    1007             return;
    1008         }
    1009     }
     885   
     886    previewVideoStartTimer->changeInterval(previewTimeout);
    1010887}
    1011888
    1012889void PlaybackBox::updateUsage(QPainter *p)
     
    13601237    if (!inTitle)
    13611238    {
    13621239        if (haveGroupInfoSet)
    1363             killPlayerSafe();
     1240            killPlayer();
    13641241       
    13651242        inTitle = true;
    13661243        paintSkipUpdate = false;
     
    19641841    return (progCache != NULL);
    19651842}
    19661843
    1967 static void *SpawnPreviewVideoThread(void *param)
     1844void PlaybackBox::killPlayer(void)
    19681845{
    1969     NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)param;
    1970     nvp->StartPlaying();
    1971     return NULL;
    1972 }
    1973 
    1974 bool PlaybackBox::killPlayer(void)
    1975 {
    1976     QMutexLocker locker(&previewVideoUnsafeKillLock);
    1977 
    1978     previewVideoPlaying = false;
    1979 
    1980     /* if we don't have nvp to deal with then we are done */
    1981     if (!previewVideoNVP)
     1846    if (previewPlayer)
    19821847    {
    1983         previewVideoKillState = kDone;
    1984         return true;
     1848        stopPlayer();
     1849        delete previewPlayer;
     1850        previewPlayer = NULL;
    19851851    }
    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;
    20261852}       
    20271853
    20281854void PlaybackBox::startPlayer(ProgramInfo *rec)
    20291855{
    2030     previewVideoPlaying = true;
    2031 
    2032     if (rec != NULL)
     1856    ignoreKeyPressEvents = true;
     1857    QMutexLocker locker(&previewVideoLock);
     1858    if (rec != NULL && previewPlayer)
    20331859    {
    2034         // Don't keep trying to open broken files when just sitting on entry
    2035         if (previewVideoBrokenRecId &&
    2036             previewVideoBrokenRecId == rec->recordid)
     1860        previewPlayer->Show();
     1861        if (!software_scaled)
     1862            previewPlayer->StartPlaying(rec, false);
     1863        if (!previewPlayer->IsPlaying())
    20371864        {
    2038             return;
     1865            software_scaled = true;
     1866            previewPlayer->StartPlaying(rec, false, true);
    20391867        }
     1868    }
     1869    ignoreKeyPressEvents = false;
     1870}
    20401871
    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);
     1872void PlaybackBox::stopPlayer(void)
     1873{
     1874    ignoreKeyPressEvents = true;
     1875    QMutexLocker locker(&previewVideoLock);
     1876    if (previewPlayer)
     1877    {
     1878        previewPlayer->StopPlaying();
     1879        previewPlayer->Hide();
    20821880    }
     1881    ignoreKeyPressEvents = false;
    20831882}
    20841883
    20851884void PlaybackBox::playSelectedPlaylist(bool random)
    20861885{
    2087     previewVideoState = kStopping;
    20881886
    20891887    if (!curitem)
    20901888        return;
     
    21151913
    21161914void PlaybackBox::playSelected()
    21171915{
    2118     previewVideoState = kStopping;
    21191916
    21201917    if (!curitem)
    21211918        return;
     
    21371934
    21381935void PlaybackBox::stopSelected()
    21391936{
    2140     previewVideoState = kStopping;
    21411937
    21421938    if (!curitem)
    21431939        return;
     
    21471943
    21481944void PlaybackBox::deleteSelected()
    21491945{
    2150     previewVideoState = kStopping;
    21511946
    21521947    if (!curitem)
    21531948        return;
     
    21611956
    21621957void PlaybackBox::upcoming()
    21631958{
    2164     previewVideoState = kStopping;
    21651959
    21661960    if (!curitem)
    21671961        return;
     
    21801974
    21811975void PlaybackBox::customEdit()
    21821976{
    2183     previewVideoState = kStopping;
    21841977
    21851978    if (!curitem)
    21861979        return;
     
    22031996
    22041997void PlaybackBox::details()
    22051998{
    2206     previewVideoState = kStopping;
    22071999
    22082000    if (!curitem)
    22092001        return;
     
    22162008
    22172009void PlaybackBox::selected()
    22182010{
    2219     previewVideoState = kStopping;
    22202011
    22212012    if (inTitle && haveGroupInfoSet)
    22222013    {
     
    22362027
    22372028void PlaybackBox::showMenu()
    22382029{
    2239     killPlayerSafe();
     2030    stopPlayer();
    22402031
    22412032    popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
    22422033                             drawPopupFgColor, drawPopupBgColor,
     
    22992090
    23002091bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist)
    23012092{
     2093    killPlayer();
     2094
    23022095    bool playCompleted = false;
    23032096
    23042097    if (!rec)
     
    23272120    ProgramInfo *tvrec = new ProgramInfo(*rec);
    23282121
    23292122    setEnabled(false);
    2330     previewVideoState = kKilling; // stop preview playback and don't restart it
    23312123    playingSomething = true;
    23322124
    23332125    playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl);
     
    23352127    playingSomething = false;
    23362128    setEnabled(true);
    23372129
    2338 
    2339     previewVideoState = kStarting; // restart playback preview
    2340 
    23412130    delete tvrec;
    23422131
    23432132    connected = FillList();
    23442133
     2134    if (previewVideoEnabled && !previewPlayer)
     2135    {
     2136        previewPlayer = PIPPlayer::Create(drawVideoBounds);
     2137        if (previewPlayer)
     2138            previewPlayer->Hide();
     2139    }
     2140
    23452141    return playCompleted;
    23462142}
    23472143
     
    23532149bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory,
    23542150                           bool forceMetadataDelete)
    23552151{
    2356     previewVideoBrokenRecId = rec->recordid;
    2357     killPlayerSafe();
     2152    stopPlayer();
    23582153
    23592154    if (playList.grep(rec->MakeUniqueKey()).count())
    23602155        togglePlayListItem(rec);
     
    23672162
    23682163void PlaybackBox::remove(ProgramInfo *toDel)
    23692164{
    2370     previewVideoState = kStopping;
    23712165
    23722166    if (delitem)
    23732167        delete delitem;
     
    23782172
    23792173void PlaybackBox::showActions(ProgramInfo *toExp)
    23802174{
    2381     killPlayer();
     2175    stopPlayer();
    23822176
    23832177    if (delitem)
    23842178        delete delitem;
     
    30412835void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program,
    30422836                            QString message, QString message2)
    30432837{
    3044     killPlayerSafe();
     2838    stopPlayer();
    30452839
    30462840    QDateTime recstartts = program->recstartts;
    30472841    QDateTime recendts = program->recendts;
     
    31502944
    31512945    cancelPopup();
    31522946
    3153     previewVideoState = kChanging;
    31542947
    3155     previewVideoRefreshTimer->start(500);
    31562948}
    31572949
    31582950void PlaybackBox::doStop(void)
     
    31642956
    31652957    stop(delitem);
    31662958
    3167     previewVideoState = kChanging;
    31682959
    3169     previewVideoRefreshTimer->start(500);
    31702960}
    31712961
    31722962void PlaybackBox::showProgramDetails()
     
    33163106
    33173107    cancelPopup();
    33183108
    3319     previewVideoState = kChanging;
    33203109
    3321     previewVideoRefreshTimer->start(500);
    33223110}
    33233111
    33243112void PlaybackBox::doPlaylistDelete(void)
     
    33623150
    33633151    bool result = doRemove(delitem, false, false);
    33643152
    3365     previewVideoState = kChanging;
    33663153
    3367     previewVideoRefreshTimer->start(500);
    33683154
    33693155    if (result)
    33703156    {
     
    33973183
    33983184    doRemove(delitem, true, true);
    33993185
    3400     previewVideoState = kChanging;
    34013186
    3402     previewVideoRefreshTimer->start(500);
    34033187}
    34043188
    34053189void PlaybackBox::doDeleteForgetHistory(void)
     
    34223206
    34233207    bool result = doRemove(delitem, true, false);
    34243208
    3425     previewVideoState = kChanging;
    34263209
    3427     previewVideoRefreshTimer->start(500);
    34283210
    34293211    if (result)
    34303212    {
     
    34993281    delete delitem;
    35003282    delitem = NULL;
    35013283
    3502     previewVideoState = kChanging;
    3503 
    35043284    connected = FillList();     
    35053285    update(drawListBounds);
    35063286}
     
    35213301    delete delitem;
    35223302    delitem = NULL;
    35233303
    3524     previewVideoState = kChanging;
    35253304
    35263305    connected = FillList();     
    35273306    update(drawListBounds);
     
    35703349
    35713350    cancelPopup();
    35723351
    3573     previewVideoState = kChanging;
    35743352}
    35753353
    35763354void PlaybackBox::toggleView(ViewMask itemMask, bool setOn)
     
    35903368    if (!rec)
    35913369        return;
    35923370
    3593     previewVideoState = kStopping;
    3594 
    35953371    if (!rec)
    35963372        return;
    35973373
     
    36883464    update(drawListBounds);
    36893465}
    36903466
     3467void PlaybackBox::refreshVideo(void)
     3468{
     3469    if (previewPlayer &&
     3470        previewPlayer->IsPlaying() &&
     3471        previewPlayer->UsingNullVideo())
     3472    {
     3473        QMutexLocker locker(&previewVideoLock);
     3474        previewPlayer->GetARGBFrame();
     3475    }
     3476}
     3477
    36913478void PlaybackBox::timeout(void)
    36923479{
    36933480    if (titleList.count() <= 1)
    36943481        return;
    36953482
    3696     if (previewVideoEnabled)
    3697         update(drawVideoBounds);
     3483    if (previewPlayer)
     3484    {
     3485        if (expectingPopup ||
     3486            !(this == gContext->GetMainWindow()->currentWidget()))
     3487        {
     3488            return;
     3489        }
     3490        else if (previewPlayer->GetNVP() == NULL)
     3491            startPlayer(curitem);
     3492        else if (!previewPlayer->IsPlaying())
     3493            stopPlayer();
     3494    }       
    36983495}
    36993496
    37003497void PlaybackBox::processNetworkControlCommands(void)
     
    42864083        return;
    42874084    }
    42884085
    4289     killPlayerSafe();
    4290 
    42914086    iconhelp->addLayout(grid);
    42924087
    42934088    QButton *button = iconhelp->addButton(tr("Ok"));
     
    42974092
    42984093    delete iconhelp;
    42994094
    4300     previewVideoState = kChanging;
    43014095
    43024096    paintSkipUpdate = false;
    43034097    paintSkipCount = 2;
     
    43174111    QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false);
    43184112    label->setAlignment(Qt::AlignCenter);
    43194113
    4320     killPlayerSafe();
     4114    stopPlayer();
    43214115
    43224116}
    43234117
     
    43424136    paintSkipUpdate = false;
    43434137    paintSkipCount = 2;
    43444138
    4345     previewVideoState = kChanging;
    4346 
    43474139    setActiveWindow();
    43484140
    43494141    if (delitem)
  • programs/mythfrontend/globalsettings.cpp

     
    18391839    return gc;
    18401840}
    18411841
    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 
    18521842static HostCheckBox *PlayBoxTransparency()
    18531843{
    18541844    HostCheckBox *gc = new HostCheckBox("PlayBoxTransparency");
     
    41874177    pbox->addChild(PreviewPixmapOffset());
    41884178    pbox->addChild(PreviewFromBookmark());
    41894179    pbox->addChild(PlaybackPreview());
    4190     pbox->addChild(PlaybackPreviewLowCPU());
    41914180    pbox->addChild(PBBStartInTitle());
    41924181    pbox->addChild(PBBShowGroupSummary());
    41934182    addChild(pbox);
  • programs/mythfrontend/playbackbox.h

     
    2626class QTimer;
    2727class ProgramInfo;
    2828class PreviewGenerator;
     29class PIPPlayer;
    2930
    3031class LayerSet;
    3132
     
    108109   
    109110  protected slots:
    110111    void timeout(void);
     112    void refreshVideo(void);
    111113
    112114    void cursorLeft();
    113115    void cursorRight();
     
    267269    ProgramInfo *findMatchingProg(QString key);
    268270    ProgramInfo *findMatchingProg(QString chanid, QString recstartts);
    269271
    270     bool killPlayer(void);
    271     void killPlayerSafe(void);
     272    void killPlayer(void);
    272273    void startPlayer(ProgramInfo *rec);
     274    void stopPlayer(void);
    273275
    274276    bool doRemove(ProgramInfo *, bool forgetHistory, bool forceMetadataDelete);
    275277    void promptEndOfRecording(ProgramInfo *);
     
    420422    QPixmap             paintBackgroundPixmap;
    421423
    422424    // 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;
    435425
    436     mutable QMutex      previewVideoKillLock;
    437     mutable QMutex      previewVideoUnsafeKillLock;
    438     killStateType       previewVideoKillState;
    439     MythTimer           previewVideoKillTimeout;
     426    PIPPlayer *previewPlayer;
     427    QTimer *previewVideoStartTimer; // if this elapses start the PIP.
     428    QTimer *previewVideoRefreshTimer; // refresh software scaled PIP
     429    bool previewVideoEnabled;
     430    QMutex previewVideoLock;
     431    int previewTimeout;
     432    bool software_scaled; // pip is software scaled.
    440433
    441434    // Preview Pixmap Variables ///////////////////////////////////////////////
    442435    bool                previewPixmapEnabled;