Ticket #843: pipplayer.diff

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

playbackbox preview set to play 30sec of the show. if using nullvideoout and pip is live tv, increase prebuffer to 20 from 4. this helps the pip fps reduction work for software scaled live tv pip. couple of bug fixes. added some user notifications (pip failure, toggle active window change, toggle denial if main window is a recording)

  • 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
     
    494496bool NuppelVideoPlayer::InitVideo(void)
    495497{
    496498    InitFilters();
     499
     500    PIPType piptype = kPIPOff;
     501
    497502    if (using_null_videoout)
    498503    {
    499504        videoOutput = new VideoOutputNull();
     505        if (ispip)
     506        {
     507            if (m_tv)
     508            {
     509                if (livetv)
     510                    piptype = kPIPOnLiveTV;
     511                else
     512                    piptype = kPIPOnTV;
     513            }
     514            else
     515                piptype = kPIPOn;
     516
     517            videoOutput->SetAsPIP(piptype);
     518        }
     519   
     520           
    500521        if (!videoOutput->Init(video_width, video_height, video_aspect,
    501522                               0, 0, 0, 0, 0, 0))
    502523        {
     
    540561            return false;
    541562        }
    542563
     564        if (ispip)
     565        {
     566            if (m_tv)
     567                piptype = kPIPOnTV;
     568            else
     569                piptype = kPIPOn;
     570           
     571            videoOutput->SetAsPIP(piptype);
     572        }
     573
    543574        if (!videoOutput->Init(video_width, video_height, video_aspect,
    544575                               widget->winId(), 0, 0, widget->width(),
    545576                               widget->height(), 0))
    546577        {
    547578            errored = true;
     579        }
     580       
     581        if (errored && ispip)
     582        {
     583            softwareScalingPIP = true;
     584            delete videoOutput;
     585            videoOutput = NULL;
     586            errored = true;
    548587            return false;
    549588        }
    550589
     
    636675{
    637676    QString errMsg = QString::null;
    638677
    639     if ((audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
     678    if (ispip || (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
    640679    {
    641680        VERBOSE(VB_IMPORTANT, LOC +
    642681                QString("Disabling Audio, params(%1,%2,%3)")
     
    756795
    757796void NuppelVideoPlayer::AutoDeint(VideoFrame *frame)
    758797{
    759     if (!frame || m_scan_locked)
     798    if (!frame || m_scan_locked || ispip)
    760799        return;
    761800
    762801    if (frame->interlaced_frame)
     
    798837{
    799838    QMutexLocker locker(&videofiltersLock);
    800839
    801     if (!videoOutput || !videosync)
     840    if (!videoOutput || !videosync || ispip)
    802841        return; // hopefully this will be called again later...
    803842
    804843    m_scan_locked = (scan != kScan_Detect);
     
    10591098
    10601099void NuppelVideoPlayer::InitFilters(void)
    10611100{
     1101    if (ispip)
     1102        return;
     1103
    10621104    VideoFrameType itmp = FMT_YV12;
    10631105    VideoFrameType otmp = FMT_YV12;
    10641106    int btmp;
     
    20782120{
    20792121    float diverge = 0.0f;
    20802122
     2123    if (ispip && framesPlayed % 2)
     2124    {
     2125        videosync->AdvanceTrigger();
     2126        framesPlayed++;
     2127        if (!using_null_videoout)
     2128            videoOutput->SetFramesPlayed(framesPlayed + 1);
     2129        return;
     2130    }
     2131
    20812132    VideoFrame *buffer = videoOutput->GetLastShownFrame();
    20822133    if (!buffer)
    20832134    {
     
    25532604    else if (videoOutput)
    25542605    {
    25552606        // Set up deinterlacing in the video output method
    2556         m_double_framerate =
    2557             (videoOutput->SetupDeinterlace(true) &&
    2558              videoOutput->NeedsDoubleFramerate());
    2559 
     2607        if (ispip)
     2608        {
     2609            m_double_framerate = false;
     2610            videoOutput->SetupDeinterlace(true, "onefield");
     2611        }
     2612        else
     2613        {
     2614            m_double_framerate =
     2615                (videoOutput->SetupDeinterlace(true) &&
     2616                videoOutput->NeedsDoubleFramerate());
     2617        }
     2618       
    25602619        videosync = VideoSync::BestMethod(
    25612620            videoOutput, fr_int, rf_int, m_double_framerate);
    25622621
     
    25892648        {
    25902649            pipplayer = setpipplayer;
    25912650            needsetpipplayer = false;
     2651            if (m_tv)
     2652                m_tv->PIPPlayerWake();
    25922653        }
    25932654
    25942655        if (ringBuffer->isDVD())
     
    30493110
    30503111    if (!InitVideo())
    30513112    {
    3052         qApp->lock();
    3053         DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
     3113        if (!ispip)
     3114        {
     3115            qApp->lock();
     3116            DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
    30543117                                   QObject::tr("Unable to initialize video."));
    3055         dialog->AddButton(QObject::tr("Return to menu."));
    3056         dialog->exec();
    3057         delete dialog;
     3118            dialog->AddButton(QObject::tr("Return to menu."));
     3119            dialog->exec();
     3120            delete dialog;
     3121            qApp->unlock();
     3122        }
    30583123
    3059         qApp->unlock();
    3060 
    30613124        if (audioOutput)
    30623125        {
    30633126            delete audioOutput;
     
    36563719    int numFrames = totalFrames;
    36573720
    36583721    if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE)
    3659         numFrames = (m_playbackinfo->endts.toTime_t() -
    3660                     m_playbackinfo->recstartts.toTime_t()) * video_frame_rate;
     3722        numFrames = (int)((m_playbackinfo->endts.toTime_t() -
     3723                    m_playbackinfo->recstartts.toTime_t()) * video_frame_rate);
    36613724
    36623725    int offset = (int) round(0.14 * (numFrames / video_frame_rate));
    36633726
     
    36803743
    36813744void NuppelVideoPlayer::SetBookmark(void)
    36823745{
    3683     if (!m_playbackinfo || !osd)
     3746    if (!m_playbackinfo)
    36843747        return;
    36853748
    36863749    m_playbackinfo->SetBookmark(framesPlayed);
    3687     osd->SetSettingsText(QObject::tr("Position Saved"), 1);
     3750    if (osd)
     3751    {
     3752        osd->SetSettingsText(QObject::tr("Position Saved"), 1);
    36883753
    3689     struct StatusPosInfo posInfo;
    3690     calcSliderPos(posInfo);
    3691     osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2);
     3754        struct StatusPosInfo posInfo;
     3755        calcSliderPos(posInfo);
     3756        osd->ShowStatus(posInfo, false, QObject::tr("Position"), 2);
     3757    }
    36923758}
    36933759
    36943760void 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;
     16class TV;
     17
     18class PIPPlayer
     19{
     20    public:
     21        PIPPlayer(void);
     22        ~PIPPlayer(void);
     23        static PIPPlayer *Create(const QRect &rect);
     24        static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location);
     25        bool StartPlaying(ProgramInfo *rec = NULL,
     26                            bool piptype = false,
     27                            bool nullvideo = false,
     28                            TV *parent = NULL);
     29        void StopPlaying();
     30        bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); }
     31        bool IsSameProgram(ProgramInfo *rec);
     32        RingBuffer          *GetRingBuffer(void) { return piprbuffer; }
     33        RemoteEncoder       *GetRecorder(void) { return piprecorder; }
     34        LiveTVChain         *GetLiveTVChain(void) { return piptvchain; }
     35        NuppelVideoPlayer   *GetNVP(void) { return pipnvp; }
     36        ProgramInfo         *GetProgramInfo(void) { return piprecinfo; }
     37        void SetRingBuffer(RingBuffer *rbuffer);
     38        void SetLiveTVChain(LiveTVChain *tvchain);
     39        void SetRecorder(RemoteEncoder  *recorder);
     40        void SetProgramInfo(ProgramInfo *pginfo);
     41        void SetReinit(bool change) { reinit = change; }
     42        bool IsLiveTV(void) { return islivetv; }
     43        bool IsHidden(void);
     44        void Hide(void);
     45        void Show(void);
     46        bool UsingNullVideo(void) { return using_nullvideo; }
     47        void GetARGBFrame(void);
     48        QSize GetVideoDimensions(void)
     49                { return QSize(video_width, video_height); }
     50        bool IsPaused(void) { return paused; }
     51        void Pause(void);
     52        void Play(float speed = 1.0);
     53       
     54
     55    private:
     56        bool StartRecorder(RemoteEncoder *rec, int maxWait);
     57        void Reinitialize(void);
     58        void Init(QRect rect, QString name);
     59
     60    private:
     61        RemoteEncoder *piprecorder;
     62        RingBuffer *piprbuffer;
     63        LiveTVChain  *piptvchain;
     64        ProgramInfo *piprecinfo;
     65        NuppelVideoPlayer *pipnvp;
     66        pthread_t videoThread;
     67        pthread_t pipdecode;
     68        QWidget *pipWindow;
     69        bool islivetv;
     70        bool reinit;
     71        bool using_nullvideo;
     72        int video_width;
     73        int video_height;
     74        bool paused;
     75};
     76
     77#endif
     78#ifndef PIPPLAYER_H
     79#define PIPPLAYER_H
     80
     81#include <qpainter.h>
     82#include "NuppelVideoPlayer.h"
     83#include "RingBuffer.h"
     84#include "programinfo.h"
     85#include "livetvchain.h"
     86#include "remoteencoder.h"
     87
     88class RingBuffer;
     89class ProgramInfo;
     90class LiveTVChain;
     91class RemoteEncoder;
     92class NuppelVideoPlayer;
     93
     94class PIPPlayer
     95{
     96    public:
     97        PIPPlayer(void);
     98        ~PIPPlayer(void);
     99        static PIPPlayer *Create(const QRect &rect);
     100        static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location);
     101        bool StartPlaying(ProgramInfo *rec = NULL,
     102                            bool piptype = false,
     103                            bool nullvideo = false);
     104        void StopPlaying();
     105        bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); }
     106        void SetFrameRate(double fps);
     107        bool IsSameProgram(ProgramInfo *rec);
     108        RingBuffer          *GetRingBuffer(void) { return piprbuffer; }
     109        RemoteEncoder       *GetRecorder(void) { return piprecorder; }
     110        LiveTVChain         *GetLiveTVChain(void) { return piptvchain; }
     111        NuppelVideoPlayer   *GetNVP(void) { return pipnvp; }
     112        ProgramInfo         *GetProgramInfo(void) { return piprecinfo; }
     113        void SetRingBuffer(RingBuffer *rbuffer);
     114        void SetLiveTVChain(LiveTVChain *tvchain);
     115        void SetRecorder(RemoteEncoder  *recorder);
     116        void SetProgramInfo(ProgramInfo *pginfo);
     117        void SetReinit(bool change) { reinit = change; }
     118        bool IsLiveTV(void) { return islivetv; }
     119        bool IsHidden(void);
     120        void Hide(void);
     121        void Show(void);
     122        bool UsingNullVideo(void) { return using_nullvideo; }
     123        void DisplaySoftwareScaledImage(void);
     124       
     125
     126    private:
     127        bool StartRecorder(RemoteEncoder *rec, int maxWait);
     128        void Reinitialize(void);
     129        void Init(QRect rect, QString name);
     130
     131    private:
     132        RemoteEncoder *piprecorder;
     133        RingBuffer *piprbuffer;
     134        LiveTVChain  *piptvchain;
     135        ProgramInfo *piprecinfo;
     136        NuppelVideoPlayer *pipnvp;
     137        pthread_t videoThread;
     138        pthread_t pipdecode;
     139        QWidget *pipWindow;
     140        bool islivetv;
     141        bool reinit;
     142        bool using_nullvideo;
     143};
     144
     145#endif
  • libs/libmythtv/NuppelVideoPlayer.h

     
    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->StartPlaying(NULL, true, false, this);
     3157        if (pipplayer->IsPlaying())
    32233158        {
    3224             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP failed to locate recorder");
    3225             if (testrec)
    3226                 delete testrec;
     3159            pipplayer->Show();
     3160            pipplayer->GetNVP()->DiscardVideoFrames(true);
    32273161            return;
    32283162        }
    3229 
    3230         testrec->Setup();
    3231 
    3232         piptvchain = new LiveTVChain();
    3233         piptvchain->InitializeNewChain("PIP"+gContext->GetHostName());
    3234         testrec->SpawnLiveTV(piptvchain->GetID(), true);
    3235         piptvchain->ReloadAll();
    3236         playbackinfo = piptvchain->GetProgramAt(-1);
    3237         if (!playbackinfo)
    3238         {
    3239             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP not successfully started");
    3240             delete testrec;
    3241             piptvchain->DestroyChain();
    3242             delete piptvchain;
    3243             piptvchain = NULL;
    3244         }
    32453163        else
    32463164        {
    3247             QString playbackURL = playbackinfo->GetPlaybackURL();
    3248 
    3249             piptvchain->SetProgram(playbackinfo);
    3250             piprbuffer = new RingBuffer(playbackURL, false);
    3251             piprbuffer->SetLiveMode(piptvchain);
    3252         }
    3253 
    3254         piprecorder = testrec;
    3255 
    3256         if (StartRecorder(piprecorder, -1))
    3257         {
    3258             SetupPipPlayer();
    3259             VERBOSE(VB_PLAYBACK, "PiP Waiting for NVP");
    3260             pthread_create(&pipdecode, NULL, SpawnDecode, pipnvp);
    3261             while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive())
     3165            QSize pipdim = pipplayer->GetVideoDimensions();
     3166            VideoOutput *vid = nvp->getVideoOutput();
     3167            if (vid &&
     3168                vid->IsResolutionSupported(pipdim.width(), pipdim.height()))
    32623169            {
    3263                 piptvchain->ReloadAll();
    3264                 usleep(5000);
     3170                if (pipplayer->GetNVP() &&
     3171                    pipplayer->GetNVP()->PIPSoftwareScaling() &&
     3172                    nvp->getVideoOutput() &&
     3173                    nvp->getVideoOutput()->hasXVAcceleration())
     3174                {
     3175                    pipplayer->StartPlaying(NULL, true, true, this);
     3176                    if (pipplayer->IsPlaying())
     3177                    {
     3178                        pipplayer->Hide();
     3179                        activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3180                        pipplayerCond.wait();
     3181                        pipplayer->GetNVP()->DiscardVideoFrames(true);
     3182                        return;
     3183                    }
     3184                }
    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         }
     3187        if (GetOSD())
     3188            GetOSD()->SetSettingsText(tr("PIP Failed to Start"), 3);
    32853189    }
    3286     else
     3190   
     3191    if (IsPIPActiveNVP())
     3192        ToggleActiveWindow();
     3193
     3194    if (nvp->HasPIPPlayer())
    32873195    {
    3288         if (activenvp != nvp)
    3289             ToggleActiveWindow();
    3290 
    3291         nvp->SetPipPlayer(NULL);
    3292         while (!nvp->PipPlayerSet())
    3293             usleep(50);
    3294 
    3295         piprbuffer->StopReads();
    3296         piprbuffer->Pause();
    3297         while (!piprbuffer->isPaused())
    3298             usleep(50);
    3299 
    3300         pipnvp->StopPlaying();
    3301 
    3302         piprecorder->StopLiveTV();
    3303 
    3304         TeardownPipPlayer();
    3305 
    3306         SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3196        activenvp->SetPIPPlayer(NULL);
     3197        pipplayerCond.wait();
    33073198    }
     3199 
     3200    if (pipplayer->IsPlaying() &&
     3201        !pipplayer->IsLiveTV())
     3202    {
     3203        pipplayer->GetNVP()->SetBookmark();
     3204    }
     3205   
     3206    delete pipplayer;
     3207    pipplayer = NULL;
    33083208}
    33093209
    33103210void TV::ToggleActiveWindow(void)
    33113211{
    3312     if (!pipnvp)
     3212    // toggleactivewindow works only if the main window is live tv.
     3213    // problem is playbackinfo and internalstate management.
     3214    if (!pipplayer  || !pipplayer->GetNVP() ||
     3215        (!IsPIPActiveNVP() && StateIsPlaying(internalState)))
     3216    {
     3217        if (GetOSD())
     3218            GetOSD()->SetSettingsText("Toggle PIP Not Allowed", 3);
    33133219        return;
    3314 
     3220    }
     3221   
    33153222    lockTimerOn = false;
    3316     if (activenvp == nvp)
     3223    LiveTVChain *piptvchain = NULL;
     3224 
     3225    if (!IsPIPActiveNVP())
    33173226    {
    3318         activenvp = pipnvp;
    3319         activerbuffer = piprbuffer;
    3320         activerecorder = piprecorder;
     3227       
     3228        activenvp      = pipplayer->GetNVP();
     3229        activerbuffer  = pipplayer->GetRingBuffer();
     3230        activerecorder = pipplayer->GetRecorder();
     3231        piptvchain     = pipplayer->GetLiveTVChain();
     3232        internalState  = GetPIPState(pipplayer);
     3233        if (pipplayer->GetProgramInfo() && !pipplayer->IsLiveTV())
     3234            SetCurrentlyPlaying(pipplayer->GetProgramInfo());
     3235        if (GetOSD())
     3236            GetOSD()->SetSettingsText("Toggle Active Window: PIP", 3);
    33213237    }
    33223238    else
    33233239    {
    3324         activenvp = nvp;
    3325         activerbuffer = prbuffer;
     3240        activenvp      = nvp;
     3241        activerbuffer  = prbuffer;
    33263242        activerecorder = recorder;
     3243        internalState  = kState_WatchingLiveTV;
     3244        if (GetOSD())
     3245            GetOSD()->SetSettingsText("Toggle Active Window: Main", 3);
    33273246    }
    3328     LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    3329     ProgramInfo *pginfo = chain->GetProgramAt(-1);
    3330     if (pginfo)
    3331     {
    3332         SetCurrentlyPlaying(pginfo);
    3333         delete pginfo;
    3334     }
     3247
     3248   if (activerecorder)
     3249   {
     3250        LiveTVChain *chain  = (activenvp == nvp) ? tvchain : piptvchain;
     3251        ProgramInfo *pginfo = chain->GetProgramAt(-1);
     3252        if (pginfo)
     3253        {
     3254            SetCurrentlyPlaying(pginfo);
     3255            delete pginfo;
     3256        }
     3257   }
    33353258}
    33363259
     3260
    33373261struct pip_info
    33383262{
    33393263    RingBuffer    *buffer;
    33403264    RemoteEncoder *recorder;
    33413265    LiveTVChain   *chain;
    33423266    long long      frame;
     3267    ProgramInfo   *pginfo;
    33433268};
    33443269
    33453270void TV::SwapPIP(void)
    33463271{
    3347     if (!pipnvp || !piptvchain || !tvchain)
     3272    if (!pipplayer)
     3273    {
     3274        if (GetOSD())
     3275            GetOSD()->SetSettingsText("PIP Not Present", 3);
    33483276        return;
     3277    }
     3278    if (IsPIPActiveNVP())
     3279        ToggleActiveWindow();
     3280   
     3281    bool use_nullvideo = pipplayer->UsingNullVideo();
     3282    bool pipislivetv = StateIsLiveTV(internalState);
     3283   
     3284    if (paused)
     3285        DoPause();
     3286    StopFFRew();
     3287    NormalSpeed();
    33493288
    3350     lockTimerOn = false;
    3351 
     3289   if (playbackinfo)
     3290       playbackinfo->setIgnoreBookmark(false);
     3291   if (pipplayer->GetProgramInfo())
     3292       pipplayer->GetProgramInfo()->setIgnoreBookmark(false);
     3293   
     3294   // set the bookmark
     3295    activenvp->SetBookmark();
     3296    pipplayer->GetNVP()->SetBookmark();
     3297   
    33523298    struct pip_info main, pip;
    3353     main.buffer   = prbuffer;
    3354     main.recorder = recorder;
    3355     main.chain    = tvchain;
    3356     main.frame    = nvp->GetFramesPlayed();
    3357     pip.buffer    = piprbuffer;
    3358     pip.recorder  = piprecorder;
    3359     pip.chain     = piptvchain;
    3360     pip.frame     = pipnvp->GetFramesPlayed();
    3361 
     3299    main.buffer      = prbuffer;
     3300    main.recorder    = recorder;
     3301    main.chain       = tvchain;
     3302    main.frame       = nvp->GetFramesPlayed();
     3303    if (StateIsPlaying(internalState))
     3304        main.pginfo = new ProgramInfo(*playbackinfo);
     3305    else
     3306        main.pginfo = NULL;
     3307   
     3308    pip.buffer       = pipplayer->GetRingBuffer();
     3309    pip.recorder     = pipplayer->GetRecorder();
     3310    pip.chain        = pipplayer->GetLiveTVChain();
     3311    pip.frame        = pipplayer->GetNVP()->GetFramesPlayed();
     3312    if (!pipplayer->IsLiveTV())
     3313        pip.pginfo   = new ProgramInfo(*pipplayer->GetProgramInfo());
     3314    else
     3315        pip.pginfo   = NULL;
     3316 
     3317    pipplayer->Hide();
     3318    if (use_nullvideo)
     3319    {
     3320        activenvp->SetPIPPlayer(NULL);
     3321        pipplayerCond.wait();
     3322    }
     3323    pipplayer->SetReinit(false);
     3324    pipplayer->StopPlaying();
     3325   
    33623326    prbuffer->Pause();
    33633327    prbuffer->WaitForPause();
    33643328
    3365     piprbuffer->Pause();
    3366     piprbuffer->WaitForPause();
     3329    nvp->StopPlaying();
    33673330
    3368     nvp->StopPlaying();
    3369     pipnvp->StopPlaying();
    33703331    {
    3371         QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd...
     3332        QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd..
    33723333        pthread_join(decode, NULL);
    33733334        delete nvp;
    33743335        nvp = NULL;
    3375         pthread_join(pipdecode, NULL);
    3376         delete pipnvp;
    3377         pipnvp = NULL;
    33783336    }
    33793337
     3338    if (playbackinfo)
     3339        delete playbackinfo;
     3340   
    33803341    activerbuffer  = prbuffer = pip.buffer;
    33813342    activerecorder = recorder = pip.recorder;
    33823343    tvchain                   = pip.chain;
     3344    playbackinfo              = pip.pginfo;
     3345    internalState             = GetPIPState(pipplayer);
    33833346
    3384     piprbuffer  = main.buffer;
    3385     piprecorder = main.recorder;
    3386     piptvchain  = main.chain;
    3387 
     3347    pipplayer->SetRingBuffer(main.buffer);
     3348    pipplayer->SetRecorder(main.recorder);
     3349    pipplayer->SetLiveTVChain(main.chain);
     3350    pipplayer->SetProgramInfo(main.pginfo);
     3351   
     3352    VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1")
     3353            .arg(StateToString(internalState)));
     3354   
    33883355    prbuffer->Seek(0, SEEK_SET);
    33893356    prbuffer->Unpause();
    3390     StartPlayer(false);
     3357
     3358    if (internalState == kState_WatchingRecording)
     3359        StartPlayer(true);
     3360    else
     3361        StartPlayer(false);
     3362
    33913363    activenvp = nvp;
    3392     nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3364    usleep(10000);
     3365    if (tvchain)
     3366    {
     3367        nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3368        nvp->DiscardVideoFrames(true);
     3369    }
     3370   
     3371    pipplayer->GetRingBuffer()->Seek(0, SEEK_SET);
     3372    pipplayer->GetRingBuffer()->Unpause();
     3373 
     3374    if (use_nullvideo)
     3375    {
     3376        pipplayer->StartPlaying(main.pginfo, pipislivetv, true, this);
     3377        if (pipplayer->IsPlaying())
     3378            activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3379    }
     3380    else
     3381        pipplayer->StartPlaying(main.pginfo, pipislivetv, this);
    33933382
    3394     piprbuffer->Seek(0, SEEK_SET);
    3395     piprbuffer->Unpause();
    3396     SetupPipPlayer();
    3397     VERBOSE(VB_PLAYBACK, "PiP Waiting for NVP -- restart");
    3398     pthread_create(&pipdecode, NULL, SpawnDecode, pipnvp);
    3399     while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive())
     3383    if (pipplayer->IsPlaying())
    34003384    {
    3401         piptvchain->ReloadAll();
    3402         usleep(5000);
     3385        if (!use_nullvideo)
     3386            pipplayer->Show();
     3387        if (pipplayer->GetLiveTVChain())
     3388        {
     3389            pipplayer->GetLiveTVChain()->ReloadAll();
     3390            usleep(5000);
     3391        }
    34033392    }
    3404     VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");
    3405     pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());
    34063393
    3407     if (pipnvp->IsDecoderThreadAlive())
    3408         nvp->SetPipPlayer(pipnvp);
    3409     else
     3394    if (internalState == kState_WatchingLiveTV)
     3395        SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV);
     3396
     3397    if (pipplayer->IsLiveTV())
     3398        SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3399
     3400    if (pipplayer->GetLiveTVChain())
    34103401    {
    3411         VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start");
    3412         TeardownPipPlayer();
     3402        NuppelVideoPlayer *pipnvp = pipplayer->GetNVP();
     3403        float pipframerate = pipplayer->GetRecorder()->GetFrameRate();
     3404        pipnvp->FastForward(main.frame/pipframerate);
     3405        pipnvp->DiscardVideoFrames(true);
    34133406    }
    34143407
    3415     ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
    3416     if (pginfo)
     3408    if (tvchain)
    34173409    {
    3418         SetCurrentlyPlaying(pginfo);
    3419         delete pginfo;
     3410        ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
     3411        if (pginfo)
     3412        {
     3413            SetCurrentlyPlaying(pginfo);
     3414            delete pginfo;
     3415        }
    34203416    }
     3417    pipplayer->SetReinit(true);
    34213418}
    34223419
     3420TVState TV::GetPIPState(PIPPlayer *player)
     3421{
     3422    if (player->IsLiveTV())
     3423        return kState_WatchingLiveTV;
     3424    else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0))
     3425        return kState_WatchingRecording;
     3426    else
     3427        return kState_WatchingPreRecorded;
     3428}
     3429
    34233430void TV::DoPlay(void)
    34243431{
    34253432    float time = 0.0;
     
    34673474
    34683475void TV::DoPause(bool showOSD)
    34693476{
     3477    QMutexLocker locker(&stateLock);
    34703478    if (activerbuffer->InDVDMenuOrStillFrame())
    34713479        return;
    34723480
     3481    if (IsPIPActiveNVP())
     3482    {
     3483        if (pipplayer->IsPaused())
     3484            pipplayer->Play();
     3485        else
     3486            pipplayer->Pause();
     3487        return;
     3488    }
     3489   
    34733490    speed_index = 0;
    34743491    float time = 0.0;
    34753492
    34763493    if (paused)
     3494    {
    34773495        activenvp->Play(normal_speed, true);
     3496        if (pipplayer)
     3497            pipplayer->Play(normal_speed);
     3498    }
    34783499    else
    34793500    {
    34803501        if (doing_ff_rew)
     
    34853506        }
    34863507       
    34873508        activenvp->Pause();
     3509        if (pipplayer)
     3510            pipplayer->Pause();
    34883511    }
    34893512
    34903513    paused = !paused;
     
    38493872
    38503873    RemoteEncoder *testrec = NULL;
    38513874
    3852     if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
     3875    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer)
    38533876        return;
    38543877
    38553878    if (/*chanid || */!channum.isEmpty())
     
    45294552    if (showStatus)
    45304553    {
    45314554        osd->HideAll();
    4532         if (nvp)
     4555        if (activenvp)
    45334556        {
    45344557            struct StatusPosInfo posInfo;
    4535             nvp->calcSliderPos(posInfo);
     4558            activenvp->calcSliderPos(posInfo);
    45364559            osd->ShowStatus(posInfo, false, tr("Position"),
    45374560                              osd_prog_info_timeout);
    45384561            update_osd_pos = true;
     
    45674590
    45684591void TV::UpdateOSDSeekMessage(const QString &mesg, int disptime)
    45694592{
    4570     if (activenvp != nvp)
     4593    if (activenvp != nvp || !prbuffer)
    45714594        return;
    45724595
    45734596    struct StatusPosInfo posInfo;
     
    49674990    {
    49684991        bool stayPaused = paused;
    49694992        if (!paused)
    4970             DoPause();
     4993            DoPause(false);
    49714994
    49724995        switch (editType)
    49734996        {
     
    50025025        }
    50035026
    50045027        if (!stayPaused)
    5005             DoPause();
     5028            DoPause(false);
    50065029    }
    50075030
    50085031    // Resize the window back to the MythTV Player size
     
    53695392                menurunning = false;
    53705393                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    53715394            }
    5372             else if (piprecorder &&
    5373                      cardnum == piprecorder->GetRecorderNumber())
     5395            else if (pipplayer && pipplayer->GetRecorder() &&
     5396                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53745397            {
    53755398                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
    53765399                TogglePIPView();
     
    53885411                wantsToQuit = false;
    53895412                exitPlayer = true;
    53905413            }
    5391             else if (piprecorder &&
    5392                      cardnum == piprecorder->GetRecorderNumber())
     5414            else if (pipplayer && pipplayer->GetRecorder() &&
     5415                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53935416            {
    53945417                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
    53955418                TogglePIPView();
     
    54055428            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
    54065429
    54075430            if ((recorder    && cardnum == recorder->GetRecorderNumber()) ||
    5408                 (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     5431                (pipplayer && pipplayer->GetRecorder() &&
     5432                 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()))
    54095433            {
    54105434                if (watch)
    54115435                {
     
    54145438                    if (pi.FromStringList(list, 0))
    54155439                        SetPseudoLiveTV(s, &pi, kPseudoChangeChannel);
    54165440
    5417                     if (!s && pipnvp)
     5441                    if (!s && pipplayer)
    54185442                        TogglePIPView();
    54195443                }
    54205444                else
     
    64086432
    64096433void TV::ShowOSDTreeMenu(void)
    64106434{
     6435    if (IsPIPActiveNVP())
     6436        return;
     6437
    64116438    BuildOSDTreeMenu();
    64126439
    64136440    if (GetOSD())
     
    64366463
    64376464    if (StateIsLiveTV(GetState()))
    64386465    {
    6439         bool freeRecorders = (pipnvp != NULL);
     6466        bool freeRecorders = (pipplayer != NULL);
    64406467        if (!freeRecorders)
    64416468            freeRecorders = RemoteGetFreeRecorderCount();
    64426469
     
    70767103{
    70777104    VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()");
    70787105
     7106    LiveTVChain *piptvchain = NULL;
     7107    if (pipplayer)
     7108        piptvchain = pipplayer->GetLiveTVChain();
     7109
    70797110    LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    70807111
    70817112    if (activenvp && chain)
  • libs/libmythtv/videoout_null.cpp

     
    8888    if ((width <= 0) || (height <= 0))
    8989        return false;
    9090
     91    int prebufferframes;
     92    if (piptype == kPIPOnLiveTV)
     93        prebufferframes = 20;
     94    else
     95        prebufferframes = kPrebufferFramesSmall;
     96   
    9197    vbuffers.Init(kNumBuffers, true, kNeedFreeFrames,
    9298                  kPrebufferFramesNormal, kPrebufferFramesSmall,
    93                   kKeepPrebuffer);
     99                  prebufferframes);
    94100    VideoOutput::Init(width, height, aspect, winid,
    95101                      winx, winy, winw, winh, embedid);
    96102
  • 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,
     100                        bool piptype, bool nullvideo,
     101                        TV *parent)
     102{
     103
     104    using_nullvideo = nullvideo;
     105    islivetv = piptype;
     106 
     107    if (reinit)
     108        Reinitialize();
     109
     110    RemoteEncoder *testrec = NULL;
     111   
     112    VERBOSE(VB_PLAYBACK, LOC +
     113            QString("PIP is for %1").arg((islivetv) ? "live tv":"a recording"));
     114
     115    if (islivetv)
     116    {
     117        if (!(piprecorder && piprbuffer && piptvchain))
     118        {
     119            testrec = RemoteRequestRecorder();
     120
     121            if (!testrec || !testrec->IsValidRecorder())
     122            {
     123                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP failed to locate recorder");
     124                if (testrec)
     125                    delete testrec;
     126                return false;
     127            }
     128
     129            testrec->Setup();
     130
     131            piptvchain = new LiveTVChain();
     132            piptvchain->InitializeNewChain("PIP"+gContext->GetHostName());
     133            testrec->SpawnLiveTV(piptvchain->GetID(), true);
     134            piptvchain->ReloadAll();
     135            piprecinfo = piptvchain->GetProgramAt(-1);
     136            if (!piprecinfo)
     137            {
     138                VERBOSE(VB_IMPORTANT, LOC_ERR +
     139                        "PIP cannot find live tv programinfo. Exiting");
     140                delete testrec;
     141                piptvchain->DestroyChain();
     142                delete piptvchain;
     143                return false;
     144            }
     145            else
     146            {
     147                QString playbackURL = piprecinfo->GetPlaybackURL();
     148                piptvchain->SetProgram(piprecinfo);
     149                piprbuffer = new RingBuffer(playbackURL, false);
     150                piprbuffer->SetLiveMode(piptvchain);
     151            }
     152
     153            piprecorder = testrec;
     154       
     155            if (!StartRecorder(piprecorder, -1))
     156            {
     157                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP recorder failed to start");
     158                return false;
     159            }
     160        }
     161    }
     162    else // pip is not Live TV
     163    {
     164        if (!piprecinfo)
     165            piprecinfo = new ProgramInfo(*rec);
     166        if (!piprbuffer)
     167            piprbuffer = new RingBuffer(piprecinfo->pathname, false, false, 1);
     168        if (!piprbuffer->IsOpen())
     169        {
     170            VERBOSE(VB_IMPORTANT, LOC_ERR +
     171                QString("Failed to open Ringbuffer %1")
     172                .arg(piprecinfo->pathname));
     173            return false;
     174        }
     175    }
     176
     177    // when starting pipplayer for the first time, always start
     178    // from the beginning
     179    if (reinit && piprecinfo)
     180        piprecinfo->setIgnoreBookmark(true);
     181       
     182    pipnvp = new NuppelVideoPlayer("pip player", piprecinfo);
     183    pipnvp->SetParentWidget(pipWindow);
     184    pipnvp->SetRingBuffer(piprbuffer);
     185    if (parent)
     186        pipnvp->SetParentPlayer(parent);
     187    if (islivetv)
     188    {
     189        pipnvp->SetRecorder(piprecorder);
     190        pipnvp->SetLiveTVChain(piptvchain);
     191    }
     192    else
     193        pipnvp->SetLength(piprecinfo->CalculateLength());
     194       
     195
     196    // setAsPIP is true if null video output is used
     197    // PIP will be embedded in XV
     198    if (using_nullvideo)
     199    {
     200        pipnvp->SetAsPIP(true);
     201    }
     202    else
     203        pipnvp->SetAsPIP(false);
     204
     205    VERBOSE(VB_PLAYBACK, "PIP Waiting for NVP");
     206    pthread_create(&pipdecode, NULL, SpawnPIPVideoThread, pipnvp);
     207    int maxWait = 10000;
     208    MythTimer t;
     209    t.start();
     210    while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive() &&
     211            t.elapsed() < maxWait)
     212    {
     213        usleep(5000);
     214    }
     215   
     216    video_width = pipnvp->GetVideoWidth();
     217    video_height = pipnvp->GetVideoHeight();
     218   
     219    if (!pipnvp->IsPlaying())
     220    {
     221        VERBOSE(VB_PLAYBACK, LOC_ERR + "PIP NVP Failed to Start");
     222        return false;
     223    }
     224   
     225    VERBOSE(VB_PLAYBACK, LOC + "PIP NVP Started");
     226    return true;
     227}
     228
     229void PIPPlayer::StopPlaying(void)
     230{
     231   
     232    if (!pipnvp)
     233        return;
     234
     235    if (pipnvp->IsPlaying())
     236    {
     237        if (reinit)
     238            piprbuffer->StopReads();
     239        piprbuffer->Pause();
     240        piprbuffer->WaitForPause();
     241        pipnvp->StopPlaying();
     242    }
     243   
     244    VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): Stopped Playing");
     245    {
     246        pthread_join(pipdecode, NULL);
     247        delete pipnvp;
     248        pipnvp = NULL;
     249    }
     250
     251    if (reinit)
     252    {
     253        if (islivetv && piprecorder )
     254            piprecorder->StopLiveTV();
     255   
     256        Reinitialize();
     257    }
     258   
     259    VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): NVP deleted");
     260}
     261
     262/*
     263 * \brief set pip ringbuffer if pip is not playing
     264 */
     265void PIPPlayer::SetRingBuffer(RingBuffer *rbuffer)
     266{
     267    if (!IsPlaying())
     268        piprbuffer = rbuffer;
     269}
     270
     271/*
     272 * \brief set pip tvchain if pip is not playing
     273 */
     274void PIPPlayer::SetLiveTVChain(LiveTVChain *tvchain)
     275{
     276    if (!IsPlaying())
     277        piptvchain = tvchain;
     278}
     279
     280/*
     281 * \brief set pip recorder if pip is not playing
     282 */
     283void PIPPlayer::SetRecorder(RemoteEncoder  *recorder)
     284{
     285    if (!IsPlaying())
     286        piprecorder = recorder;
     287}
     288
     289void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo)
     290{
     291    if (!IsPlaying())
     292    {
     293        if (piprecinfo)
     294            delete piprecinfo;
     295        piprecinfo = pginfo;
     296    }
     297}
     298
     299bool PIPPlayer::IsSameProgram(ProgramInfo *rec)
     300{
     301    if (!rec || !piprecinfo)
     302        return false;
     303
     304    if (piprecinfo->IsSameProgram(*rec))
     305        return true;
     306   
     307    return false;
     308}
     309
     310bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait)
     311{
     312    maxWait = (maxWait <= 0) ? 20000 : maxWait;
     313    MythTimer t;
     314    t.start();
     315    while (rec && !rec->IsRecording() && t.elapsed() < maxWait)
     316        usleep(5000);
     317    if (rec && !rec->IsRecording())
     318    {
     319        VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out");
     320        return false;
     321    }
     322    return true;
     323}
     324
     325void PIPPlayer::Hide(void)
     326{
     327    if (pipWindow && pipWindow->isVisible())
     328        pipWindow->hide();
     329}
     330
     331void PIPPlayer::Show(void)
     332{   
     333    if (pipWindow && pipWindow->isHidden())
     334        pipWindow->show();
     335}
     336
     337bool PIPPlayer::IsHidden(void)
     338{
     339    if (pipWindow && pipWindow->isHidden())
     340        return true;
     341    return false;
     342}
     343
     344void PIPPlayer::GetARGBFrame(void)
     345{
     346    if (!using_nullvideo)
     347        return;
     348   
     349    QPainter p(pipWindow);
     350    QSize size = pipWindow->size();
     351    float saspect = ((float)size.width())/ ((float)size.height());
     352    float vaspect = pipnvp->GetVideoAspect();
     353    size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
     354    size.setHeight(((size.height() + 7) / 8) * 8);
     355    size.setWidth( ((size.width()  + 7) / 8) * 8);
     356    const QImage &img = pipnvp->GetARGBFrame(size);
     357    p.drawImage(0, 0, img);
     358}
     359
     360void PIPPlayer::Pause(void)
     361{
     362    if (IsPlaying() && !paused)
     363    {
     364        pipnvp->Pause();
     365        paused = true;
     366    }
     367}
     368
     369void PIPPlayer::Play(float speed)
     370{
     371    if (IsPlaying() && paused)
     372    {
     373        pipnvp->Play(speed);
     374        paused = false;
     375    }
     376}
     377
  • libs/libmythtv/videoout_xv.h

     
    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    kPIPOnLiveTV // Live TV used in TV Mode
     88};
     89
    8290enum ZoomDirections
    8391{
    8492    kZoomHome = 0,
     
    190198    virtual void GetOSDBounds(QRect &visible, QRect &total,
    191199                              float &pixelAspect, float &fontScale) const;
    192200
     201    virtual bool IsResolutionSupported(int width, int height);
     202
    193203    /// \brief Returns current display's frame refresh period in microseconds.
    194204    ///        e.g. 1000000 / frame_rate_in_Hz
    195205    virtual int GetRefreshRate(void) = 0;
     
    225235    bool AllowPreviewEPG(void) { return allowpreviewepg; }
    226236
    227237    /// \brief Returns true iff Motion Compensation acceleration is available.
    228     virtual bool hasMCAcceleration() const { return false; }
     238    virtual bool hasMCAcceleration(void) const { return false; }
    229239    /// \brief Returns true iff Inverse Discrete Cosine Transform acceleration
    230240    ///        is available.
    231     virtual bool hasIDCTAcceleration() const { return false; }
     241    virtual bool hasIDCTAcceleration(void) const { return false; }
    232242    /// \brief Returns true iff VLD acceleration is available.
    233     virtual bool hasVLDAcceleration() const { return false; }
     243    virtual bool hasVLDAcceleration(void) const { return false; }
     244    /// \brief Returns true if XV acceleration is available.
     245    virtual bool hasXVAcceleration(void) const { return false; }
    234246
    235247    /// \brief Sets the number of frames played
    236248    virtual void SetFramesPlayed(long long fp) { framesPlayed = fp; };
     
    308320    /// \brief Tells the player to resize the video frame (used for ITV)
    309321    void SetVideoResize(const QRect &videoRect);
    310322
     323    /// \brief returns QRect of PIP based on PIPLocation
     324    virtual QRect GetPIPRect(int location, NuppelVideoPlayer *pipplayer = NULL);
     325
     326    /// set PIP Type
     327    void SetAsPIP(PIPType setting) { piptype = setting; }
     328       
     329
    311330  protected:
    312331    void InitBuffers(int numdecode, bool extra_for_pause, int need_free,
    313332                     int needprebuffer_normal, int needprebuffer_small,
     
    384403    QSize   pip_video_size;
    385404    unsigned char      *pip_tmp_buf;
    386405    ImgReSampleContext *pip_scaling_context;
     406    PIPType    piptype;
    387407
    388408    // Video resizing (for ITV)
    389409    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;