Ticket #843: pipplayer.7.diff

File pipplayer.7.diff, 86.6 KB (added by skamithi, 17 years ago)

2nd attempt to control fps of pip..cuts fps in 1/2. see code changes in nvp::avsync. works for recorded shows. doesn't work well for live tv pip. problem with livetv.. it doesn't report framesplayed consistently until i ffw/rew or hit pause on the pip. trying to resolve this issue.

  • 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;
     
    20782099{
    20792100    float diverge = 0.0f;
    20802101
     2102    if (ispip && framesPlayed % 2)
     2103    {
     2104        videosync->AdvanceTrigger();
     2105        framesPlayed++;
     2106        if (!using_null_videoout)
     2107            videoOutput->SetFramesPlayed(framesPlayed + 1);
     2108        return;
     2109    }
     2110
    20812111    VideoFrame *buffer = videoOutput->GetLastShownFrame();
    20822112    if (!buffer)
    20832113    {
     
    25532583    else if (videoOutput)
    25542584    {
    25552585        // Set up deinterlacing in the video output method
    2556         m_double_framerate =
    2557             (videoOutput->SetupDeinterlace(true) &&
    2558              videoOutput->NeedsDoubleFramerate());
    2559 
     2586        if (ispip)
     2587        {
     2588            m_double_framerate = false;
     2589            videoOutput->SetupDeinterlace(true, "onefield");
     2590        }
     2591        else
     2592        {
     2593            m_double_framerate =
     2594                (videoOutput->SetupDeinterlace(true) &&
     2595                videoOutput->NeedsDoubleFramerate());
     2596        }
     2597       
    25602598        videosync = VideoSync::BestMethod(
    25612599            videoOutput, fr_int, rf_int, m_double_framerate);
    25622600
     
    25892627        {
    25902628            pipplayer = setpipplayer;
    25912629            needsetpipplayer = false;
     2630            if (m_tv)
     2631                m_tv->PIPPlayerWake();
    25922632        }
    25932633
    25942634        if (ringBuffer->isDVD())
     
    30493089
    30503090    if (!InitVideo())
    30513091    {
    3052         qApp->lock();
    3053         DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
     3092        if (!ispip)
     3093        {
     3094            qApp->lock();
     3095            DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
    30543096                                   QObject::tr("Unable to initialize video."));
    3055         dialog->AddButton(QObject::tr("Return to menu."));
    3056         dialog->exec();
    3057         delete dialog;
     3097            dialog->AddButton(QObject::tr("Return to menu."));
     3098            dialog->exec();
     3099            delete dialog;
     3100            qApp->unlock();
     3101        }
    30583102
    3059         qApp->unlock();
    3060 
    30613103        if (audioOutput)
    30623104        {
    30633105            delete audioOutput;
     
    36563698    int numFrames = totalFrames;
    36573699
    36583700    if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE)
    3659         numFrames = (m_playbackinfo->endts.toTime_t() -
    3660                     m_playbackinfo->recstartts.toTime_t()) * video_frame_rate;
     3701        numFrames = (int)((m_playbackinfo->endts.toTime_t() -
     3702                    m_playbackinfo->recstartts.toTime_t()) * video_frame_rate);
    36613703
    36623704    int offset = (int) round(0.14 * (numFrames / video_frame_rate));
    36633705
     
    36803722
    36813723void NuppelVideoPlayer::SetBookmark(void)
    36823724{
    3683     if (!m_playbackinfo || !osd)
     3725    if (!m_playbackinfo)
    36843726        return;
    36853727
    36863728    m_playbackinfo->SetBookmark(framesPlayed);
    3687     osd->SetSettingsText(QObject::tr("Position Saved"), 1);
     3729    if (osd)
     3730    {
     3731        osd->SetSettingsText(QObject::tr("Position Saved"), 1);
    36883732
    3689     struct StatusPosInfo posInfo;
    3690     calcSliderPos(posInfo);
    3691     osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2);
     3733        struct StatusPosInfo posInfo;
     3734        calcSliderPos(posInfo);
     3735        osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2);
     3736    }
    36923737}
    36933738
    36943739void 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();
     3161            pipplayer->GetNVP()->DiscardVideoFrames(true);
    32273162            return;
    32283163        }
    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         }
    32453164        else
    32463165        {
    3247             QString playbackURL = playbackinfo->GetPlaybackURL();
    3248 
    3249             piptvchain->SetProgram(playbackinfo);
    3250             piprbuffer = new RingBuffer(playbackURL, false);
    3251             piprbuffer->SetLiveMode(piptvchain);
    3252         }
    3253 
    3254         piprecorder = testrec;
    3255 
    3256         if (StartRecorder(piprecorder, -1))
    3257         {
    3258             SetupPipPlayer();
    3259             VERBOSE(VB_PLAYBACK, "PiP Waiting for NVP");
    3260             pthread_create(&pipdecode, NULL, SpawnDecode, pipnvp);
    3261             while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive())
     3166            QSize pipdim = pipplayer->GetVideoDimensions();
     3167            VideoOutput *vid = nvp->getVideoOutput();
     3168            if (vid &&
     3169                vid->IsResolutionSupported(pipdim.width(), pipdim.height()))
    32623170            {
    3263                 piptvchain->ReloadAll();
    3264                 usleep(5000);
     3171                if (pipplayer->GetNVP() &&
     3172                    pipplayer->GetNVP()->PIPSoftwareScaling() &&
     3173                    nvp->getVideoOutput() &&
     3174                    nvp->getVideoOutput()->hasXVAcceleration())
     3175                {
     3176                    pipplayer->StartPlaying(NULL, true, true);
     3177                    if (pipplayer->IsPlaying())
     3178                    {
     3179                        activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3180                        pipplayerCond.wait();
     3181                        pipplayer->GetNVP()->DiscardVideoFrames(true);
     3182                        return;
     3183                    }
     3184                }
    32653185            }
    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             }
    32793186        }
    3280         else
    3281         {
    3282             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start");
    3283             TeardownPipPlayer();
    3284         }
    32853187    }
    3286     else
     3188   
     3189    if (IsPIPActiveNVP())
     3190        ToggleActiveWindow();
     3191
     3192    if (nvp->HasPIPPlayer())
    32873193    {
    3288         if (activenvp != nvp)
    3289             ToggleActiveWindow();
    3290 
    3291         nvp->SetPipPlayer(NULL);
    3292         while (!nvp->PipPlayerSet())
    3293             usleep(50);
    3294 
    3295         piprbuffer->StopReads();
    3296         piprbuffer->Pause();
    3297         while (!piprbuffer->isPaused())
    3298             usleep(50);
    3299 
    3300         pipnvp->StopPlaying();
    3301 
    3302         piprecorder->StopLiveTV();
    3303 
    3304         TeardownPipPlayer();
    3305 
    3306         SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3194        activenvp->SetPIPPlayer(NULL);
     3195        pipplayerCond.wait();
    33073196    }
     3197   
     3198    delete pipplayer;
     3199    pipplayer = NULL;
    33083200}
    33093201
    33103202void TV::ToggleActiveWindow(void)
    33113203{
    3312     if (!pipnvp)
     3204    // toggleactivewindow works only if the main window is live tv.
     3205    // problem is playbackinfo and internalstate management.
     3206    if (!pipplayer  || !pipplayer->GetNVP() ||
     3207        (!IsPIPActiveNVP() && StateIsPlaying(internalState)))
     3208    {
    33133209        return;
    3314 
     3210    }
     3211   
    33153212    lockTimerOn = false;
    3316     if (activenvp == nvp)
     3213    LiveTVChain *piptvchain = NULL;
     3214 
     3215    if (!IsPIPActiveNVP())
    33173216    {
    3318         activenvp = pipnvp;
    3319         activerbuffer = piprbuffer;
    3320         activerecorder = piprecorder;
     3217       
     3218        activenvp      = pipplayer->GetNVP();
     3219        activerbuffer  = pipplayer->GetRingBuffer();
     3220        activerecorder = pipplayer->GetRecorder();
     3221        piptvchain     = pipplayer->GetLiveTVChain();
     3222        internalState  = GetPIPState(pipplayer);
     3223        if (pipplayer->GetProgramInfo() && !pipplayer->IsLiveTV())
     3224            SetCurrentlyPlaying(pipplayer->GetProgramInfo());
    33213225    }
    33223226    else
    33233227    {
    3324         activenvp = nvp;
    3325         activerbuffer = prbuffer;
     3228        activenvp      = nvp;
     3229        activerbuffer  = prbuffer;
    33263230        activerecorder = recorder;
     3231        internalState  = kState_WatchingLiveTV;
    33273232    }
    3328     LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    3329     ProgramInfo *pginfo = chain->GetProgramAt(-1);
    3330     if (pginfo)
    3331     {
    3332         SetCurrentlyPlaying(pginfo);
    3333         delete pginfo;
    3334     }
     3233
     3234   if (activerecorder)
     3235   {
     3236        LiveTVChain *chain  = (activenvp == nvp) ? tvchain : piptvchain;
     3237        ProgramInfo *pginfo = chain->GetProgramAt(-1);
     3238        if (pginfo)
     3239        {
     3240            SetCurrentlyPlaying(pginfo);
     3241            delete pginfo;
     3242        }
     3243   }
    33353244}
    33363245
     3246
    33373247struct pip_info
    33383248{
    33393249    RingBuffer    *buffer;
    33403250    RemoteEncoder *recorder;
    33413251    LiveTVChain   *chain;
    33423252    long long      frame;
     3253    ProgramInfo   *pginfo;
    33433254};
    33443255
    33453256void TV::SwapPIP(void)
    33463257{
    3347     if (!pipnvp || !piptvchain || !tvchain)
     3258    if (!pipplayer)
     3259        // TODO print something on OSD informing use that PIP swap cannot be done
    33483260        return;
    33493261
    3350     lockTimerOn = false;
     3262    if (IsPIPActiveNVP())
     3263        ToggleActiveWindow();
     3264   
     3265    bool use_nullvideo = pipplayer->UsingNullVideo();
     3266    bool pipislivetv = StateIsLiveTV(internalState);
     3267   
     3268    if (paused)
     3269        DoPause();
     3270    StopFFRew();
     3271    NormalSpeed();
    33513272
     3273   if (playbackinfo)
     3274       playbackinfo->setIgnoreBookmark(false);
     3275   if (pipplayer->GetProgramInfo())
     3276       pipplayer->GetProgramInfo()->setIgnoreBookmark(false);
     3277   
     3278   // set the bookmark
     3279    activenvp->SetBookmark();
     3280    pipplayer->GetNVP()->SetBookmark();
     3281   
    33523282    struct pip_info main, pip;
    3353     main.buffer   = prbuffer;
    3354     main.recorder = recorder;
    3355     main.chain    = tvchain;
    3356     main.frame    = nvp->GetFramesPlayed();
    3357     pip.buffer    = piprbuffer;
    3358     pip.recorder  = piprecorder;
    3359     pip.chain     = piptvchain;
    3360     pip.frame     = pipnvp->GetFramesPlayed();
    3361 
     3283    main.buffer      = prbuffer;
     3284    main.recorder    = recorder;
     3285    main.chain       = tvchain;
     3286    main.frame       = nvp->GetFramesPlayed();
     3287    if (StateIsPlaying(internalState))
     3288        main.pginfo = new ProgramInfo(*playbackinfo);
     3289    else
     3290        main.pginfo = NULL;
     3291   
     3292    pip.buffer       = pipplayer->GetRingBuffer();
     3293    pip.recorder     = pipplayer->GetRecorder();
     3294    pip.chain        = pipplayer->GetLiveTVChain();
     3295    pip.frame        = pipplayer->GetNVP()->GetFramesPlayed();
     3296    if (!pipplayer->IsLiveTV())
     3297        pip.pginfo   = new ProgramInfo(*pipplayer->GetProgramInfo());
     3298    else
     3299        pip.pginfo   = NULL;
     3300 
     3301    pipplayer->Hide();
     3302    if (use_nullvideo)
     3303    {
     3304        activenvp->SetPIPPlayer(NULL);
     3305        pipplayerCond.wait();
     3306    }
     3307    pipplayer->SetReinit(false);
     3308    pipplayer->StopPlaying();
     3309   
    33623310    prbuffer->Pause();
    33633311    prbuffer->WaitForPause();
    33643312
    3365     piprbuffer->Pause();
    3366     piprbuffer->WaitForPause();
     3313    nvp->StopPlaying();
    33673314
    3368     nvp->StopPlaying();
    3369     pipnvp->StopPlaying();
    33703315    {
    3371         QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd...
     3316        QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd..
    33723317        pthread_join(decode, NULL);
    33733318        delete nvp;
    33743319        nvp = NULL;
    3375         pthread_join(pipdecode, NULL);
    3376         delete pipnvp;
    3377         pipnvp = NULL;
    33783320    }
    33793321
     3322    if (playbackinfo)
     3323        delete playbackinfo;
     3324   
    33803325    activerbuffer  = prbuffer = pip.buffer;
    33813326    activerecorder = recorder = pip.recorder;
    33823327    tvchain                   = pip.chain;
     3328    playbackinfo              = pip.pginfo;
     3329    internalState             = GetPIPState(pipplayer);
    33833330
    3384     piprbuffer  = main.buffer;
    3385     piprecorder = main.recorder;
    3386     piptvchain  = main.chain;
    3387 
     3331    pipplayer->SetRingBuffer(main.buffer);
     3332    pipplayer->SetRecorder(main.recorder);
     3333    pipplayer->SetLiveTVChain(main.chain);
     3334    pipplayer->SetProgramInfo(main.pginfo);
     3335   
     3336    VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1")
     3337            .arg(StateToString(internalState)));
     3338   
    33883339    prbuffer->Seek(0, SEEK_SET);
    33893340    prbuffer->Unpause();
    3390     StartPlayer(false);
     3341
     3342    if (internalState == kState_WatchingRecording)
     3343        StartPlayer(true);
     3344    else
     3345        StartPlayer(false);
     3346
    33913347    activenvp = nvp;
    3392     nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3348    usleep(10000);
     3349    if (tvchain)
     3350    {
     3351        nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3352        nvp->DiscardVideoFrames(true);
     3353    }
     3354   
     3355    pipplayer->GetRingBuffer()->Seek(0, SEEK_SET);
     3356    pipplayer->GetRingBuffer()->Unpause();
     3357 
     3358    if (use_nullvideo)
     3359    {
     3360        pipplayer->StartPlaying(main.pginfo, pipislivetv, true);
     3361        if (pipplayer->IsPlaying())
     3362            activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3363    }
     3364    else
     3365        pipplayer->StartPlaying(main.pginfo, pipislivetv);
    33933366
    3394     piprbuffer->Seek(0, SEEK_SET);
    3395     piprbuffer->Unpause();
    3396     SetupPipPlayer();
    3397     VERBOSE(VB_PLAYBACK, "PiP Waiting for NVP -- restart");
    3398     pthread_create(&pipdecode, NULL, SpawnDecode, pipnvp);
    3399     while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive())
     3367    if (pipplayer->IsPlaying())
    34003368    {
    3401         piptvchain->ReloadAll();
    3402         usleep(5000);
     3369        if (!use_nullvideo)
     3370            pipplayer->Show();
     3371        if (pipplayer->GetLiveTVChain())
     3372        {
     3373            pipplayer->GetLiveTVChain()->ReloadAll();
     3374            usleep(5000);
     3375        }
    34033376    }
    3404     VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");
    3405     pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());
    34063377
    3407     if (pipnvp->IsDecoderThreadAlive())
    3408         nvp->SetPipPlayer(pipnvp);
    3409     else
     3378    if (internalState == kState_WatchingLiveTV)
     3379        SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV);
     3380
     3381    if (pipplayer->IsLiveTV())
     3382        SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3383
     3384    if (pipplayer->GetLiveTVChain())
    34103385    {
    3411         VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start");
    3412         TeardownPipPlayer();
     3386        NuppelVideoPlayer *pipnvp = pipplayer->GetNVP();
     3387        float pipframerate = pipplayer->GetRecorder()->GetFrameRate();
     3388        pipnvp->FastForward(main.frame/pipframerate);
     3389        pipnvp->DiscardVideoFrames(true);
    34133390    }
    34143391
    3415     ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
    3416     if (pginfo)
     3392    if (tvchain)
    34173393    {
    3418         SetCurrentlyPlaying(pginfo);
    3419         delete pginfo;
     3394        ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
     3395        if (pginfo)
     3396        {
     3397            SetCurrentlyPlaying(pginfo);
     3398            delete pginfo;
     3399        }
    34203400    }
     3401    pipplayer->SetReinit(true);
    34213402}
    34223403
     3404TVState TV::GetPIPState(PIPPlayer *player)
     3405{
     3406    if (player->IsLiveTV())
     3407        return kState_WatchingLiveTV;
     3408    else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0))
     3409        return kState_WatchingRecording;
     3410    else
     3411        return kState_WatchingPreRecorded;
     3412}
     3413
    34233414void TV::DoPlay(void)
    34243415{
    34253416    float time = 0.0;
     
    34673458
    34683459void TV::DoPause(bool showOSD)
    34693460{
     3461    QMutexLocker locker(&stateLock);
    34703462    if (activerbuffer->InDVDMenuOrStillFrame())
    34713463        return;
    34723464
     3465    if (IsPIPActiveNVP())
     3466    {
     3467        if (pipplayer->IsPaused())
     3468            pipplayer->Play();
     3469        else
     3470            pipplayer->Pause();
     3471        return;
     3472    }
     3473   
    34733474    speed_index = 0;
    34743475    float time = 0.0;
    34753476
    34763477    if (paused)
     3478    {
    34773479        activenvp->Play(normal_speed, true);
     3480        if (pipplayer)
     3481            pipplayer->Play(normal_speed);
     3482    }
    34783483    else
    34793484    {
    34803485        if (doing_ff_rew)
     
    34853490        }
    34863491       
    34873492        activenvp->Pause();
     3493        if (pipplayer)
     3494            pipplayer->Pause();
    34883495    }
    34893496
    34903497    paused = !paused;
     
    38493856
    38503857    RemoteEncoder *testrec = NULL;
    38513858
    3852     if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
     3859    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer)
    38533860        return;
    38543861
    38553862    if (/*chanid || */!channum.isEmpty())
     
    45294536    if (showStatus)
    45304537    {
    45314538        osd->HideAll();
    4532         if (nvp)
     4539        if (activenvp)
    45334540        {
    45344541            struct StatusPosInfo posInfo;
    4535             nvp->calcSliderPos(posInfo);
     4542            activenvp->calcSliderPos(posInfo);
    45364543            osd->ShowStatus(posInfo, false, tr("Position"),
    45374544                              osd_prog_info_timeout);
    45384545            update_osd_pos = true;
     
    45674574
    45684575void TV::UpdateOSDSeekMessage(const QString &mesg, int disptime)
    45694576{
    4570     if (activenvp != nvp)
     4577    if (activenvp != nvp || !prbuffer)
    45714578        return;
    45724579
    45734580    struct StatusPosInfo posInfo;
     
    49674974    {
    49684975        bool stayPaused = paused;
    49694976        if (!paused)
    4970             DoPause();
     4977            DoPause(false);
    49714978
    49724979        switch (editType)
    49734980        {
     
    50025009        }
    50035010
    50045011        if (!stayPaused)
    5005             DoPause();
     5012            DoPause(false);
    50065013    }
    50075014
    50085015    // Resize the window back to the MythTV Player size
     
    53695376                menurunning = false;
    53705377                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    53715378            }
    5372             else if (piprecorder &&
    5373                      cardnum == piprecorder->GetRecorderNumber())
     5379            else if (pipplayer && pipplayer->GetRecorder() &&
     5380                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53745381            {
    53755382                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
    53765383                TogglePIPView();
     
    53885395                wantsToQuit = false;
    53895396                exitPlayer = true;
    53905397            }
    5391             else if (piprecorder &&
    5392                      cardnum == piprecorder->GetRecorderNumber())
     5398            else if (pipplayer && pipplayer->GetRecorder() &&
     5399                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53935400            {
    53945401                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
    53955402                TogglePIPView();
     
    54055412            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
    54065413
    54075414            if ((recorder    && cardnum == recorder->GetRecorderNumber()) ||
    5408                 (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     5415                (pipplayer && pipplayer->GetRecorder() &&
     5416                 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()))
    54095417            {
    54105418                if (watch)
    54115419                {
     
    54145422                    if (pi.FromStringList(list, 0))
    54155423                        SetPseudoLiveTV(s, &pi, kPseudoChangeChannel);
    54165424
    5417                     if (!s && pipnvp)
     5425                    if (!s && pipplayer)
    54185426                        TogglePIPView();
    54195427                }
    54205428                else
     
    64086416
    64096417void TV::ShowOSDTreeMenu(void)
    64106418{
     6419    if (IsPIPActiveNVP())
     6420        return;
     6421
    64116422    BuildOSDTreeMenu();
    64126423
    64136424    if (GetOSD())
     
    64366447
    64376448    if (StateIsLiveTV(GetState()))
    64386449    {
    6439         bool freeRecorders = (pipnvp != NULL);
     6450        bool freeRecorders = (pipplayer != NULL);
    64406451        if (!freeRecorders)
    64416452            freeRecorders = RemoteGetFreeRecorderCount();
    64426453
     
    70767087{
    70777088    VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()");
    70787089
     7090    LiveTVChain *piptvchain = NULL;
     7091    if (pipplayer)
     7092        piptvchain = pipplayer->GetLiveTVChain();
     7093
    70797094    LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    70807095
    70817096    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 +
     1226                QString("XV PIP not supported with blended OSD. "
     1227                "Using software scaled PIP."));
     1228        return false;
     1229    }
    12211230    // Initialize the OSD, if we need to
    1222     InitOSD(db_vdisp_profile->GetOSDRenderer());
     1231    if (piptype == kPIPOff)
     1232        InitOSD(osdrenderer);
    12231233
    12241234    // Create video buffers
    12251235    bool use_xv  = (renderer.left(2) == "xv");
     
    12591269{
    12601270    needrepaint = true;
    12611271
     1272    // for PIP use software scaled image if width or height <= 64
     1273    if (piptype > kPIPOff &&
     1274        (width <= 64 || height <= 64))
     1275    {
     1276        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1277                QString("PIP Video Init Failed. Dimensions less then 64 "
     1278                        "Video width %1, Video height %2")
     1279                .arg(width).arg(height));
     1280        return false;
     1281    }
     1282       
    12621283    XV_INIT_FATAL_ERROR_TEST(winid <= 0, "Invalid Window ID.");
    12631284
    12641285    XJ_disp = MythXOpenDisplay();
     
    32673288#endif // USING_XVMC
    32683289}
    32693290
     3291bool VideoOutputXv::IsResolutionSupported(int width, int height)
     3292{
     3293    if (width == 0 || height == 0)
     3294        return false;
     3295
     3296    if (xv_port >= 0 && xv_chroma)
     3297    {
     3298        int size = 0;
     3299        int desiredsize = 0;
     3300        XvImage *img = NULL;
     3301        XShmSegmentInfo *info = new XShmSegmentInfo;
     3302        X11S(img = XvShmCreateImage(XJ_disp, xv_port, xv_chroma, 0,
     3303                width, height, info));
     3304        size = img->data_size + 64;
     3305        desiredsize =  width * height * 3 / 2;
     3306        if (img && size < desiredsize)
     3307        {
     3308            VERBOSE(VB_IMPORTANT, LOC_ERR + QString("IsResolutionSupported(): "
     3309                    "WxH %1x%2 not supported on this Xv Surface")
     3310                    .arg(width).arg(height));
     3311            XFree(img);
     3312            delete info;
     3313            return false;
     3314        }
     3315
     3316        return true;
     3317    }
     3318    return false;
     3319}
     3320       
    32703321bool VideoOutputXv::IsDisplaying(VideoFrame* frame)
    32713322{
    32723323    (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      previewPlayer(NULL), previewVideoStartTimer(new QTimer(this)),
    266267      previewVideoRefreshTimer(new QTimer(this)),
    267       previewVideoBrokenRecId(0),       previewVideoState(kStopped),
    268       previewVideoStartTimerOn(false),  previewVideoEnabled(false),
    269       previewVideoPlaying(false),       previewVideoThreadRunning(false),
    270       previewVideoKillState(kDone),
     268      previewVideoStopTimer(new QTimer(this)),
     269      previewVideoEnabled(false),
     270      previewTimeout(2000), software_scaled(false),
    271271      // Preview Image Variables
    272272      previewPixmapEnabled(false),      previewPixmap(NULL),
    273273      previewSuspend(false),            previewChanid(""),
     
    369369    connected = FillList();
    370370
    371371    // connect up timers...
    372     connect(previewVideoRefreshTimer, SIGNAL(timeout()),
     372    connect(previewVideoStartTimer,        SIGNAL(timeout()),
    373373            this,                     SLOT(timeout()));
     374    connect(previewVideoRefreshTimer,       SIGNAL(timeout()),
     375            this,                     SLOT(refreshVideo()));
     376    connect(previewVideoStopTimer,          SIGNAL(timeout()),
     377            this,                     SLOT(stopPlayer()));
    374378    connect(freeSpaceTimer,           SIGNAL(timeout()),
    375379            this,                     SLOT(setUpdateFreeSpace()));
    376380    connect(fillListTimer,            SIGNAL(timeout()),
    377381            this,                     SLOT(listChanged()));
    378382
    379383    // preview video & preview pixmap init
    380     previewVideoRefreshTimer->start(500);
    381384    previewStartts = QDateTime::currentDateTime();
    382 
    383385    // misc setup
    384386    updateBackground();
    385387    setNoErase();
     
    398400    gContext->removeListener(this);
    399401    gContext->removeCurrentLocation();
    400402
    401     if (!m_player)
    402         killPlayerSafe();
     403    killPlayer();
     404   
     405    if (previewVideoStartTimer)
     406    {
     407        previewVideoStartTimer->disconnect(this);
     408        previewVideoStartTimer->deleteLater();
     409        previewVideoStartTimer = NULL;
     410    }
    403411
    404412    if (previewVideoRefreshTimer)
    405413    {
     
    408416        previewVideoRefreshTimer = NULL;
    409417    }
    410418
     419    if (previewVideoStopTimer)
     420    {
     421        previewVideoStopTimer->disconnect(this);
     422        previewVideoStopTimer->deleteLater();
     423        previewVideoStopTimer = NULL;
     424    }
     425
    411426    if (fillListTimer)
    412427    {
    413428        fillListTimer->disconnect(this);
     
    464479        delete previewPixmap;
    465480        previewPixmap = NULL;
    466481    }
    467 }
    468482
    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;
    496483}
    497484
    498485void PlaybackBox::LoadWindow(QDomElement &element)
     
    523510            }
    524511        }
    525512    }
     513
     514    if (previewVideoEnabled)
     515    {
     516        previewPlayer = PIPPlayer::Create(drawVideoBounds);
     517        if (previewPlayer)
     518            previewPlayer->Hide();
     519        previewPixmapEnabled = true;
     520    }
    526521}
    527522
    528523void PlaybackBox::parseContainer(QDomElement &element)
     
    596591
    597592void PlaybackBox::exitWin()
    598593{
     594    killPlayer();
    599595    if (m_player)
    600596    {
    601597        if (curitem)
     
    603599        curitem = NULL;
    604600        pbbIsVisibleCond.wakeAll();
    605601    }
    606     else
    607         killPlayerSafe();
    608 
    609602    accept();
    610603}
    611604
     
    785778    QMap<QString, QString> infoMap;
    786779    QPainter tmp(&pix);
    787780       
    788     if (previewVideoPlaying)
    789         previewVideoState = kChanging;
    790781
    791782    LayerSet *container = NULL;
    792783    if (type != Delete)
     
    799790        if (curitem)
    800791            curitem->ToMap(infoMap);
    801792       
    802         if ((previewVideoEnabled == 0) &&
    803             (previewPixmapEnabled == 0))
     793        if (previewPixmapEnabled == 0)
    804794            container->UseAlternateArea(true);
    805795
    806796        container->ClearAllText();
     
    845835    tmp.end();
    846836    p->drawPixmap(pr.topLeft(), pix);
    847837
    848     previewVideoStartTimer.start();
    849     previewVideoStartTimerOn = true;
    850838}
    851839
    852840void PlaybackBox::updateInfo(QPainter *p)
     
    883871    // If we're displaying group info don't update the video.
    884872    if (inTitle && haveGroupInfoSet)
    885873        return;
    886 
     874   
    887875    /* show a still frame if the user doesn't want a video preview or nvp
    888876     * hasn't started playing the video preview yet */
    889     if (curitem && !playingSomething &&
    890         (!previewVideoEnabled             ||
    891          !previewVideoPlaying             ||
    892          (previewVideoState == kStarting) ||
    893          (previewVideoState == kChanging)))
     877    if ((curitem && previewPixmapEnabled && !previewPlayer) ||
     878         (curitem && previewPlayer && previewPlayer->IsHidden()))
    894879    {
    895880        QPixmap temp = getPixmap(curitem);
    896881        if (temp.width() > 0)
    897882            p->drawPixmap(drawVideoBounds.x(), drawVideoBounds.y(), temp);
    898883    }
    899 
    900     /* keep calling killPlayer() to handle nvp cleanup */
    901     /* until killPlayer() is done */
    902     if (previewVideoKillState != kDone && !killPlayer())
    903         return;
    904 
    905     /* if we aren't supposed to have a preview playing then always go */
    906     /* to the stopping previewVideoState */
    907     if (!previewVideoEnabled &&
    908         (previewVideoState != kKilling) && (previewVideoState != kKilled))
     884   
     885    if (curitem && previewVideoEnabled && previewPlayer &&
     886            !previewPlayer->IsHidden())
    909887    {
    910         previewVideoState = kStopping;
    911     }
    912 
    913     /* if we have no nvp and aren't playing yet */
    914     /* if we have an item we should start playing */
    915     if (!previewVideoNVP   && previewVideoEnabled  &&
    916         curitem            && !previewVideoPlaying &&
    917         (previewVideoState != kKilling) &&
    918         (previewVideoState != kKilled)  &&
    919         (previewVideoState != kStarting))
    920     {
    921         ProgramInfo *rec = curitem;
    922 
    923         if (fileExists(rec) == false)
    924         {
    925             VERBOSE(VB_IMPORTANT, QString("Error: File '%1' missing.")
    926                     .arg(rec->pathname));
    927 
    928             previewVideoState = kStopping;
    929 
    930             ProgramInfo *tmpItem = findMatchingProg(rec);
    931             if (tmpItem)
    932                 tmpItem->availableStatus = asFileNotFound;
    933 
    934             return;
    935         }
    936         previewVideoState = kStarting;
    937     }
    938 
    939     if (previewVideoState == kChanging)
    940     {
    941         if (previewVideoNVP)
    942         {
    943             killPlayer(); /* start killing the player */
    944             return;
    945         }
    946 
    947         previewVideoState = kStarting;
    948     }
    949 
    950     if ((previewVideoState == kStarting) &&
    951         (!previewVideoStartTimerOn ||
    952          (previewVideoStartTimer.elapsed() > 500)))
    953     {
    954         previewVideoStartTimerOn = false;
    955 
    956         if (!previewVideoNVP)
    957             startPlayer(curitem);
    958 
    959         if (previewVideoNVP)
    960         {
    961             if (previewVideoNVP->IsPlaying())
    962                 previewVideoState = kPlaying;
    963         }
     888        if (!previewPlayer->IsSameProgram(curitem))
     889            stopPlayer();
    964890        else
    965         {
    966             // already dead, so clean up
    967             killPlayer();
    968             return;
    969         }
     891            previewPlayer->GetNVP()->ExposeEvent();
    970892    }
    971 
    972     if ((previewVideoState == kStopping) || (previewVideoState == kKilling))
    973     {
    974         if (previewVideoNVP)
    975         {
    976             killPlayer(); /* start killing the player and exit */
    977             return;
    978         }
    979 
    980         if (previewVideoState == kKilling)
    981             previewVideoState = kKilled;
    982         else
    983             previewVideoState = kStopped;
    984     }
    985 
    986     /* if we are playing and nvp is running, then grab a new video frame */
    987     if ((previewVideoState == kPlaying) && previewVideoNVP->IsPlaying() &&
    988         !playingSomething)
    989     {
    990         QSize size = drawVideoBounds.size();
    991         float saspect = ((float)size.width()) / ((float)size.height());
    992         float vaspect = previewVideoNVP->GetVideoAspect();
    993         size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
    994         size.setHeight(((size.height() + 7) / 8) * 8);
    995         size.setWidth( ((size.width()  + 7) / 8) * 8);
    996         const QImage &img = previewVideoNVP->GetARGBFrame(size);
    997         p->drawImage(drawVideoBounds.x(), drawVideoBounds.y(), img);
    998     }
    999 
    1000     /* have we timed out waiting for nvp to start? */
    1001     if ((previewVideoState == kPlaying) && !previewVideoNVP->IsPlaying())
    1002     {
    1003         if (previewVideoPlayingTimer.elapsed() > 2000)
    1004         {
    1005             previewVideoState = kStarting;
    1006             killPlayer();
    1007             return;
    1008         }
    1009     }
     893   
     894    previewVideoStartTimer->start(previewTimeout);
    1010895}
    1011896
    1012897void PlaybackBox::updateUsage(QPainter *p)
     
    13601245    if (!inTitle)
    13611246    {
    13621247        if (haveGroupInfoSet)
    1363             killPlayerSafe();
     1248            killPlayer();
    13641249       
    13651250        inTitle = true;
    13661251        paintSkipUpdate = false;
     
    19641849    return (progCache != NULL);
    19651850}
    19661851
    1967 static void *SpawnPreviewVideoThread(void *param)
     1852void PlaybackBox::killPlayer(void)
    19681853{
    1969     NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)param;
    1970     nvp->StartPlaying();
    1971     return NULL;
    1972 }
    1973 
    1974 bool PlaybackBox::killPlayer(void)
    1975 {
    1976     QMutexLocker locker(&previewVideoUnsafeKillLock);
    1977 
    1978     previewVideoPlaying = false;
    1979 
    1980     /* if we don't have nvp to deal with then we are done */
    1981     if (!previewVideoNVP)
     1854    if (previewPlayer)
    19821855    {
    1983         previewVideoKillState = kDone;
    1984         return true;
     1856        stopPlayer();
     1857        delete previewPlayer;
     1858        previewPlayer = NULL;
    19851859    }
    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;
    20261860}       
    20271861
    20281862void PlaybackBox::startPlayer(ProgramInfo *rec)
    20291863{
    2030     previewVideoPlaying = true;
    2031 
    2032     if (rec != NULL)
     1864    ignoreKeyPressEvents = true;
     1865    QMutexLocker locker(&previewVideoLock);
     1866    previewVideoStartTimer->start(previewTimeout);
     1867    previewVideoStopTimer->start(30000);
     1868    if (rec != NULL && previewPlayer)
    20331869    {
    2034         // Don't keep trying to open broken files when just sitting on entry
    2035         if (previewVideoBrokenRecId &&
    2036             previewVideoBrokenRecId == rec->recordid)
     1870        previewPlayer->Show();
     1871        if (!software_scaled)
     1872            previewPlayer->StartPlaying(rec, false);
     1873        if (!previewPlayer->IsPlaying())
    20371874        {
    2038             return;
     1875            previewVideoRefreshTimer->start(50);
     1876            software_scaled = true;
     1877            previewPlayer->StartPlaying(rec, false, true);
    20391878        }
     1879    }
     1880    ignoreKeyPressEvents = false;
     1881}
    20401882
    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);
     1883void PlaybackBox::stopPlayer(void)
     1884{
     1885    ignoreKeyPressEvents = true;
     1886    QMutexLocker locker(&previewVideoLock);
     1887    if (previewPlayer)
     1888    {
     1889        previewVideoRefreshTimer->stop();
     1890        previewPlayer->StopPlaying();
     1891        previewPlayer->Hide();
    20821892    }
     1893    ignoreKeyPressEvents = false;
    20831894}
    20841895
    20851896void PlaybackBox::playSelectedPlaylist(bool random)
    20861897{
    2087     previewVideoState = kStopping;
    20881898
    20891899    if (!curitem)
    20901900        return;
     
    21151925
    21161926void PlaybackBox::playSelected()
    21171927{
    2118     previewVideoState = kStopping;
    21191928
    21201929    if (!curitem)
    21211930        return;
     
    21371946
    21381947void PlaybackBox::stopSelected()
    21391948{
    2140     previewVideoState = kStopping;
    21411949
    21421950    if (!curitem)
    21431951        return;
     
    21471955
    21481956void PlaybackBox::deleteSelected()
    21491957{
    2150     previewVideoState = kStopping;
    21511958
    21521959    if (!curitem)
    21531960        return;
     
    21611968
    21621969void PlaybackBox::upcoming()
    21631970{
    2164     previewVideoState = kStopping;
    21651971
    21661972    if (!curitem)
    21671973        return;
     
    21801986
    21811987void PlaybackBox::customEdit()
    21821988{
    2183     previewVideoState = kStopping;
    21841989
    21851990    if (!curitem)
    21861991        return;
     
    22032008
    22042009void PlaybackBox::details()
    22052010{
    2206     previewVideoState = kStopping;
    22072011
    22082012    if (!curitem)
    22092013        return;
     
    22162020
    22172021void PlaybackBox::selected()
    22182022{
    2219     previewVideoState = kStopping;
    22202023
    22212024    if (inTitle && haveGroupInfoSet)
    22222025    {
     
    22362039
    22372040void PlaybackBox::showMenu()
    22382041{
    2239     killPlayerSafe();
     2042    stopPlayer();
    22402043
    22412044    popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
    22422045                             drawPopupFgColor, drawPopupBgColor,
     
    22992102
    23002103bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist)
    23012104{
     2105    killPlayer();
     2106
    23022107    bool playCompleted = false;
    23032108
    23042109    if (!rec)
     
    23272132    ProgramInfo *tvrec = new ProgramInfo(*rec);
    23282133
    23292134    setEnabled(false);
    2330     previewVideoState = kKilling; // stop preview playback and don't restart it
    23312135    playingSomething = true;
    23322136
    23332137    playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl);
     
    23352139    playingSomething = false;
    23362140    setEnabled(true);
    23372141
    2338 
    2339     previewVideoState = kStarting; // restart playback preview
    2340 
    23412142    delete tvrec;
    23422143
    23432144    connected = FillList();
    23442145
     2146    if (previewVideoEnabled && !previewPlayer)
     2147    {
     2148        previewPlayer = PIPPlayer::Create(drawVideoBounds);
     2149        if (previewPlayer)
     2150            previewPlayer->Hide();
     2151    }
     2152
    23452153    return playCompleted;
    23462154}
    23472155
     
    23532161bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory,
    23542162                           bool forceMetadataDelete)
    23552163{
    2356     previewVideoBrokenRecId = rec->recordid;
    2357     killPlayerSafe();
     2164    stopPlayer();
    23582165
    23592166    if (playList.grep(rec->MakeUniqueKey()).count())
    23602167        togglePlayListItem(rec);
     
    23672174
    23682175void PlaybackBox::remove(ProgramInfo *toDel)
    23692176{
    2370     previewVideoState = kStopping;
    23712177
    23722178    if (delitem)
    23732179        delete delitem;
     
    23782184
    23792185void PlaybackBox::showActions(ProgramInfo *toExp)
    23802186{
    2381     killPlayer();
     2187    stopPlayer();
    23822188
    23832189    if (delitem)
    23842190        delete delitem;
     
    30412847void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program,
    30422848                            QString message, QString message2)
    30432849{
    3044     killPlayerSafe();
     2850    stopPlayer();
    30452851
    30462852    QDateTime recstartts = program->recstartts;
    30472853    QDateTime recendts = program->recendts;
     
    31502956
    31512957    cancelPopup();
    31522958
    3153     previewVideoState = kChanging;
    31542959
    3155     previewVideoRefreshTimer->start(500);
    31562960}
    31572961
    31582962void PlaybackBox::doStop(void)
     
    31642968
    31652969    stop(delitem);
    31662970
    3167     previewVideoState = kChanging;
    31682971
    3169     previewVideoRefreshTimer->start(500);
    31702972}
    31712973
    31722974void PlaybackBox::showProgramDetails()
     
    33163118
    33173119    cancelPopup();
    33183120
    3319     previewVideoState = kChanging;
    33203121
    3321     previewVideoRefreshTimer->start(500);
    33223122}
    33233123
    33243124void PlaybackBox::doPlaylistDelete(void)
     
    33623162
    33633163    bool result = doRemove(delitem, false, false);
    33643164
    3365     previewVideoState = kChanging;
    33663165
    3367     previewVideoRefreshTimer->start(500);
    33683166
    33693167    if (result)
    33703168    {
     
    33973195
    33983196    doRemove(delitem, true, true);
    33993197
    3400     previewVideoState = kChanging;
    34013198
    3402     previewVideoRefreshTimer->start(500);
    34033199}
    34043200
    34053201void PlaybackBox::doDeleteForgetHistory(void)
     
    34223218
    34233219    bool result = doRemove(delitem, true, false);
    34243220
    3425     previewVideoState = kChanging;
    34263221
    3427     previewVideoRefreshTimer->start(500);
    34283222
    34293223    if (result)
    34303224    {
     
    34993293    delete delitem;
    35003294    delitem = NULL;
    35013295
    3502     previewVideoState = kChanging;
    3503 
    35043296    connected = FillList();     
    35053297    update(drawListBounds);
    35063298}
     
    35213313    delete delitem;
    35223314    delitem = NULL;
    35233315
    3524     previewVideoState = kChanging;
    35253316
    35263317    connected = FillList();     
    35273318    update(drawListBounds);
     
    35703361
    35713362    cancelPopup();
    35723363
    3573     previewVideoState = kChanging;
    35743364}
    35753365
    35763366void PlaybackBox::toggleView(ViewMask itemMask, bool setOn)
     
    35903380    if (!rec)
    35913381        return;
    35923382
    3593     previewVideoState = kStopping;
    3594 
    35953383    if (!rec)
    35963384        return;
    35973385
     
    36883476    update(drawListBounds);
    36893477}
    36903478
     3479void PlaybackBox::refreshVideo(void)
     3480{
     3481    if (previewPlayer &&
     3482        previewPlayer->IsPlaying() &&
     3483        previewPlayer->UsingNullVideo())
     3484    {
     3485        QMutexLocker locker(&previewVideoLock);
     3486        previewPlayer->GetARGBFrame();
     3487    }
     3488}
     3489
    36913490void PlaybackBox::timeout(void)
    36923491{
    36933492    if (titleList.count() <= 1)
    36943493        return;
    36953494
    3696     if (previewVideoEnabled)
    3697         update(drawVideoBounds);
     3495    if (previewPlayer)
     3496    {
     3497        if (expectingPopup ||
     3498            !(this == gContext->GetMainWindow()->currentWidget()))
     3499        {
     3500            return;
     3501        }
     3502        else if (previewPlayer->GetNVP() == NULL)
     3503            startPlayer(curitem);
     3504        else if (!previewPlayer->IsPlaying())
     3505            stopPlayer();
     3506    }       
    36983507}
    36993508
     3509
    37003510void PlaybackBox::processNetworkControlCommands(void)
    37013511{
    37023512    int commands = 0;
     
    42864096        return;
    42874097    }
    42884098
    4289     killPlayerSafe();
    4290 
    42914099    iconhelp->addLayout(grid);
    42924100
    42934101    QButton *button = iconhelp->addButton(tr("Ok"));
     
    42974105
    42984106    delete iconhelp;
    42994107
    4300     previewVideoState = kChanging;
    43014108
    43024109    paintSkipUpdate = false;
    43034110    paintSkipCount = 2;
     
    43174124    QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false);
    43184125    label->setAlignment(Qt::AlignCenter);
    43194126
    4320     killPlayerSafe();
     4127    stopPlayer();
    43214128
    43224129}
    43234130
     
    43424149    paintSkipUpdate = false;
    43434150    paintSkipCount = 2;
    43444151
    4345     previewVideoState = kChanging;
    4346 
    43474152    setActiveWindow();
    43484153
    43494154    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();
     
    228230
    229231    void previewThreadDone(const QString &fn, bool &success);
    230232    void previewReady(const ProgramInfo *pginfo);
     233    void stopPlayer(void);
    231234
    232235  protected:
    233236    void paintEvent(QPaintEvent *);
     
    267270    ProgramInfo *findMatchingProg(QString key);
    268271    ProgramInfo *findMatchingProg(QString chanid, QString recstartts);
    269272
    270     bool killPlayer(void);
    271     void killPlayerSafe(void);
     273    void killPlayer(void);
    272274    void startPlayer(ProgramInfo *rec);
    273275
    274276    bool doRemove(ProgramInfo *, bool forgetHistory, bool forceMetadataDelete);
     
    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    QTimer *previewVideoStopTimer; // if this elapses restart the PIP
     430    bool previewVideoEnabled;
     431    QMutex previewVideoLock;
     432    int previewTimeout;
     433    bool software_scaled; // pip is software scaled.
    440434
    441435    // Preview Pixmap Variables ///////////////////////////////////////////////
    442436    bool                previewPixmapEnabled;