Ticket #843: pipplayer.5.diff

File pipplayer.5.diff, 78.7 KB (added by skamithi, 13 years ago)

removed my attempt to control pip fps. needs more work. turn on deinterlacing for pip. set override filter list to "linearblend".(not sure if this is the right thing). tv::toggleactivewindow enabled..only works when the main window is live tv.

  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    204204      audio_samplerate(44100),      audio_stretchfactor(1.0f),
    205205      // Picture-in-Picture
    206206      pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false),
     207      ispip(false), softwareScalingPIP(false),
    207208      // Preview window support
    208209      argb_buf(NULL),               argb_size(0,0),
    209210      yuv2argb_conv(yuv2rgb_init_mmx(32, MODE_RGB)),
     
    294295
    295296    if (m_playbackinfo)
    296297    {
    297         m_playbackinfo->MarkAsInUse(false);
     298        if (!ispip)
     299            m_playbackinfo->MarkAsInUse(false);
    298300        delete m_playbackinfo;
    299301    }
    300302
     
    540542            return false;
    541543        }
    542544
     545        if (ispip)
     546        {
     547            if (m_tv)
     548                videoOutput->SetAsPIP(kPIPOnTV);
     549            else
     550                videoOutput->SetAsPIP(kPIPOn);
     551        }
     552
    543553        if (!videoOutput->Init(video_width, video_height, video_aspect,
    544554                               widget->winId(), 0, 0, widget->width(),
    545555                               widget->height(), 0))
    546556        {
    547557            errored = true;
     558        }
     559       
     560        if (errored && !videoOutput->hasXVAcceleration() && ispip)
     561        {
     562            softwareScalingPIP = true;
     563            delete videoOutput;
     564            videoOutput = NULL;
     565            errored = true;
    548566            return false;
    549567        }
    550568
     
    636654{
    637655    QString errMsg = QString::null;
    638656
    639     if ((audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
     657    if (ispip || (audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
    640658    {
    641659        VERBOSE(VB_IMPORTANT, LOC +
    642660                QString("Disabling Audio, params(%1,%2,%3)")
     
    756774
    757775void NuppelVideoPlayer::AutoDeint(VideoFrame *frame)
    758776{
    759     if (!frame || m_scan_locked)
     777    if (!frame || m_scan_locked || ispip)
    760778        return;
    761779
    762780    if (frame->interlaced_frame)
     
    798816{
    799817    QMutexLocker locker(&videofiltersLock);
    800818
    801     if (!videoOutput || !videosync)
     819    if (!videoOutput || !videosync || ispip)
    802820        return; // hopefully this will be called again later...
    803821
    804822    m_scan_locked = (scan != kScan_Detect);
     
    10591078
    10601079void NuppelVideoPlayer::InitFilters(void)
    10611080{
     1081    if (ispip)
     1082        return;
     1083
    10621084    VideoFrameType itmp = FMT_YV12;
    10631085    VideoFrameType otmp = FMT_YV12;
    10641086    int btmp;
     
    25532575    else if (videoOutput)
    25542576    {
    25552577        // Set up deinterlacing in the video output method
    2556         m_double_framerate =
    2557             (videoOutput->SetupDeinterlace(true) &&
    2558              videoOutput->NeedsDoubleFramerate());
    2559 
     2578        if (ispip)
     2579        {
     2580            m_double_framerate = false;
     2581            videoOutput->SetupDeinterlace(true, "linearblend");
     2582        }
     2583        else
     2584        {
     2585            m_double_framerate =
     2586                (videoOutput->SetupDeinterlace(true) &&
     2587                videoOutput->NeedsDoubleFramerate());
     2588        }
     2589       
    25602590        videosync = VideoSync::BestMethod(
    25612591            videoOutput, fr_int, rf_int, m_double_framerate);
    25622592
     
    25892619        {
    25902620            pipplayer = setpipplayer;
    25912621            needsetpipplayer = false;
     2622            if (m_tv)
     2623                m_tv->PIPPlayerWake();
    25922624        }
    25932625
    25942626        if (ringBuffer->isDVD())
     
    30493081
    30503082    if (!InitVideo())
    30513083    {
    3052         qApp->lock();
    3053         DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
     3084        if (!ispip)
     3085        {
     3086            qApp->lock();
     3087            DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
    30543088                                   QObject::tr("Unable to initialize video."));
    3055         dialog->AddButton(QObject::tr("Return to menu."));
    3056         dialog->exec();
    3057         delete dialog;
     3089            dialog->AddButton(QObject::tr("Return to menu."));
     3090            dialog->exec();
     3091            delete dialog;
     3092            qApp->unlock();
     3093        }
    30583094
    3059         qApp->unlock();
    3060 
    30613095        if (audioOutput)
    30623096        {
    30633097            delete audioOutput;
     
    36563690    int numFrames = totalFrames;
    36573691
    36583692    if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE)
    3659         numFrames = (m_playbackinfo->endts.toTime_t() -
    3660                     m_playbackinfo->recstartts.toTime_t()) * video_frame_rate;
     3693        numFrames = (int)((m_playbackinfo->endts.toTime_t() -
     3694                    m_playbackinfo->recstartts.toTime_t()) * video_frame_rate);
    36613695
    36623696    int offset = (int) round(0.14 * (numFrames / video_frame_rate));
    36633697
  • 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.
     
    320321
    321322    void SetupPlayer(bool isWatchingRecording);
    322323    void TeardownPlayer(void);
    323     void SetupPipPlayer(void);
    324     void TeardownPipPlayer(void);
    325324   
    326325    void HandleStateChange(void);
    327326    bool InStateChange(void) const;
     
    331330    void TogglePIPView(void);
    332331    void ToggleActiveWindow(void);
    333332    void SwapPIP(void);
     333    TVState GetPIPState(PIPPlayer *pip);
    334334    void SwapPIPSoon(void) { needToSwapPIP = true; }
    335 
     335   
    336336    void ToggleAutoExpire(void);
    337337
    338338    void BrowseStart(void);
     
    529529
    530530    // Video Players
    531531    NuppelVideoPlayer *nvp;
    532     NuppelVideoPlayer *pipnvp;
     532    PIPPlayer  *pipplayer;
    533533    NuppelVideoPlayer *activenvp;  ///< Player to which LiveTV events are sent
    534534
     535    //PIP Stuff
     536    QWaitCondition pipplayerCond;
     537
    535538    // Remote Encoders
    536539    /// Main recorder
    537540    RemoteEncoder *recorder;
    538     /// Picture-in-Picture recorder
    539     RemoteEncoder *piprecorder;
    540541    /// Recorder to which LiveTV events are being sent
    541542    RemoteEncoder *activerecorder;
    542543    /// Main recorder to use after a successful SwitchCards() call.
     
    546547
    547548    // LiveTVChain
    548549    LiveTVChain *tvchain;
    549     LiveTVChain *piptvchain;
    550550    QStringList tvchainUpdate;
    551551    QMutex tvchainUpdateLock;
    552552
    553553    // RingBuffers
    554554    RingBuffer *prbuffer;
    555     RingBuffer *piprbuffer;
    556555    RingBuffer *activerbuffer; ///< Ringbuffer to which LiveTV events are sent
    557556
    558557    // OSD info
     
    589588    pthread_t event;
    590589    /// Video decoder thread, runs nvp's NuppelVideoPlayer::StartPlaying().
    591590    pthread_t decode;
    592     /// Picture-in-Picture video decoder thread,
    593     /// runs pipnvp's NuppelVideoPlayer::StartPlaying().
    594     pthread_t pipdecode;
    595591
    596592    /// Condition to signal that the Event thread is up and running
    597593    QWaitCondition mainLoopCond;
  • libs/libmythtv/pipplayer.h

     
     1#ifndef PIPPLAYER_H
     2#define PIPPLAYER_H
     3
     4#include <qpainter.h>
     5#include "NuppelVideoPlayer.h"
     6#include "RingBuffer.h"
     7#include "programinfo.h"
     8#include "livetvchain.h"
     9#include "remoteencoder.h"
     10
     11class RingBuffer;
     12class ProgramInfo;
     13class LiveTVChain;
     14class RemoteEncoder;
     15class NuppelVideoPlayer;
     16
     17class PIPPlayer
     18{
     19    public:
     20        PIPPlayer(void);
     21        ~PIPPlayer(void);
     22        static PIPPlayer *Create(const QRect &rect);
     23        static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location);
     24        bool StartPlaying(ProgramInfo *rec = NULL,
     25                            bool piptype = false,
     26                            bool nullvideo = false);
     27        void StopPlaying();
     28        bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); }
     29        bool IsSameProgram(ProgramInfo *rec);
     30        RingBuffer          *GetRingBuffer(void) { return piprbuffer; }
     31        RemoteEncoder       *GetRecorder(void) { return piprecorder; }
     32        LiveTVChain         *GetLiveTVChain(void) { return piptvchain; }
     33        NuppelVideoPlayer   *GetNVP(void) { return pipnvp; }
     34        ProgramInfo         *GetProgramInfo(void) { return piprecinfo; }
     35        void SetRingBuffer(RingBuffer *rbuffer);
     36        void SetLiveTVChain(LiveTVChain *tvchain);
     37        void SetRecorder(RemoteEncoder  *recorder);
     38        void SetProgramInfo(ProgramInfo *pginfo);
     39        void SetReinit(bool change) { reinit = change; }
     40        bool IsLiveTV(void) { return islivetv; }
     41        bool IsHidden(void);
     42        void Hide(void);
     43        void Show(void);
     44        bool UsingNullVideo(void) { return using_nullvideo; }
     45        void DisplaySoftwareScaledImage(void);
     46       
     47
     48    private:
     49        bool StartRecorder(RemoteEncoder *rec, int maxWait);
     50        void Reinitialize(void);
     51        void Init(QRect rect, QString name);
     52
     53    private:
     54        RemoteEncoder *piprecorder;
     55        RingBuffer *piprbuffer;
     56        LiveTVChain  *piptvchain;
     57        ProgramInfo *piprecinfo;
     58        NuppelVideoPlayer *pipnvp;
     59        pthread_t videoThread;
     60        pthread_t pipdecode;
     61        QWidget *pipWindow;
     62        bool islivetv;
     63        bool reinit;
     64        bool using_nullvideo;
     65};
     66
     67#endif
     68#ifndef PIPPLAYER_H
     69#define PIPPLAYER_H
     70
     71#include <qpainter.h>
     72#include "NuppelVideoPlayer.h"
     73#include "RingBuffer.h"
     74#include "programinfo.h"
     75#include "livetvchain.h"
     76#include "remoteencoder.h"
     77
     78class RingBuffer;
     79class ProgramInfo;
     80class LiveTVChain;
     81class RemoteEncoder;
     82class NuppelVideoPlayer;
     83
     84class PIPPlayer
     85{
     86    public:
     87        PIPPlayer(void);
     88        ~PIPPlayer(void);
     89        static PIPPlayer *Create(const QRect &rect);
     90        static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location);
     91        bool StartPlaying(ProgramInfo *rec = NULL,
     92                            bool piptype = false,
     93                            bool nullvideo = false);
     94        void StopPlaying();
     95        bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); }
     96        void SetFrameRate(double fps);
     97        bool IsSameProgram(ProgramInfo *rec);
     98        RingBuffer          *GetRingBuffer(void) { return piprbuffer; }
     99        RemoteEncoder       *GetRecorder(void) { return piprecorder; }
     100        LiveTVChain         *GetLiveTVChain(void) { return piptvchain; }
     101        NuppelVideoPlayer   *GetNVP(void) { return pipnvp; }
     102        ProgramInfo         *GetProgramInfo(void) { return piprecinfo; }
     103        void SetRingBuffer(RingBuffer *rbuffer);
     104        void SetLiveTVChain(LiveTVChain *tvchain);
     105        void SetRecorder(RemoteEncoder  *recorder);
     106        void SetProgramInfo(ProgramInfo *pginfo);
     107        void SetReinit(bool change) { reinit = change; }
     108        bool IsLiveTV(void) { return islivetv; }
     109        bool IsHidden(void);
     110        void Hide(void);
     111        void Show(void);
     112        bool UsingNullVideo(void) { return using_nullvideo; }
     113        void DisplaySoftwareScaledImage(void);
     114       
     115
     116    private:
     117        bool StartRecorder(RemoteEncoder *rec, int maxWait);
     118        void Reinitialize(void);
     119        void Init(QRect rect, QString name);
     120
     121    private:
     122        RemoteEncoder *piprecorder;
     123        RingBuffer *piprbuffer;
     124        LiveTVChain  *piptvchain;
     125        ProgramInfo *piprecinfo;
     126        NuppelVideoPlayer *pipnvp;
     127        pthread_t videoThread;
     128        pthread_t pipdecode;
     129        QWidget *pipWindow;
     130        bool islivetv;
     131        bool reinit;
     132        bool using_nullvideo;
     133};
     134
     135#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;
     
    223226    void StartPlaying(void);
    224227    void ResetPlaying(void);
    225228    void StopPlaying(void) { killplayer = true; decoder_thread_alive = false; }
     229       
    226230
    227231    // Pause stuff
    228232    void PauseDecoder(void);
     
    670674    NuppelVideoPlayer *pipplayer;
    671675    NuppelVideoPlayer *setpipplayer;
    672676    bool needsetpipplayer;
     677    bool ispip;
     678    bool softwareScalingPIP;
    673679
    674680    // Preview window support
    675681    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);
     
    699693            pthread_detach(ddMapLoader);
    700694        }
    701695    }
     696
    702697}
    703698
    704699TVState TV::GetState(void) const
     
    13791374            prbuffer->Pause();
    13801375            prbuffer->WaitForPause();
    13811376        }
    1382 
    1383         if (piprbuffer)
    1384         {
    1385             piprbuffer->StopReads();
    1386             piprbuffer->Pause();
    1387             piprbuffer->WaitForPause();
    1388         }
    13891377    }
    13901378
    13911379    if (stopPlayers)
     
    13931381        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (1/2)");
    13941382        if (nvp)
    13951383            nvp->StopPlaying();
    1396 
    1397         if (pipnvp)
    1398             pipnvp->StopPlaying();
    13991384    }
    14001385
    14011386    if (stopRecorders)
     
    14031388        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping recorder[s]");
    14041389        if (recorder)
    14051390            recorder->StopLiveTV();
    1406 
    1407         if (piprecorder)
    1408             piprecorder->StopLiveTV();
    14091391    }
    14101392
    14111393    if (stopPlayers)
     
    14131395        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (2/2)");
    14141396        if (nvp)
    14151397            TeardownPlayer();
    1416 
    1417         if (pipnvp)
    1418             TeardownPipPlayer();
     1398        if (pipplayer)
     1399        {
     1400            delete pipplayer;
     1401            pipplayer = NULL;
     1402        }
    14191403    }
    14201404    VERBOSE(VB_PLAYBACK, LOC + "StopStuff() -- end");
    14211405}
     
    14971481    return filters;
    14981482}
    14991483
    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 
    15221484void TV::TeardownPlayer(void)
    15231485{
    15241486    if (nvp)
     
    15681530        prbuffer = activerbuffer = NULL;
    15691531    }
    15701532
    1571     if (piprbuffer)
    1572     {
    1573         delete piprbuffer;
    1574         piprbuffer = NULL;
    1575     }
    1576 
    15771533    if (tvchain)
    15781534    {
    15791535        tvchain->DestroyChain();
     
    15821538    }
    15831539}
    15841540
    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 
    16241541void *TV::EventThread(void *param)
    16251542{
    16261543    TV *thetv = (TV *)param;
     
    16861603                        if (nvp->GetTVChain())
    16871604                            nvp->CheckTVChain();
    16881605                    }
    1689                     if (piptvchain && pipnvp && *it == piptvchain->GetID())
     1606                    if (pipplayer && pipplayer->IsLiveTV()
     1607                            && *it == pipplayer->GetLiveTVChain()->GetID())
    16901608                    {
     1609                        LiveTVChain *piptvchain = pipplayer->GetLiveTVChain();
    16911610                        piptvchain->ReloadAll();
    1692                         if (pipnvp->GetTVChain())
    1693                             pipnvp->CheckTVChain();
     1611                        if (pipplayer->GetNVP()->GetTVChain())
     1612                            pipplayer->GetNVP()->CheckTVChain();
    16941613                    }
    16951614                }
    16961615                tvchainUpdate.clear();
     
    17521671            wantsToQuit = true;
    17531672        }
    17541673
     1674        if (pipplayer && !pipplayer->IsPlaying())
     1675            TogglePIPView();
     1676
    17551677        if (StateIsPlaying(internalState))
    17561678        {
    17571679#ifdef USING_VALGRIND
     
    18591781            prevChan = tmp;
    18601782            pseudoLiveTVState[i] = kPseudoRecording;
    18611783
    1862             if (i && pipnvp)
     1784            if (i && pipplayer)
    18631785                TogglePIPView();
    18641786        }
    18651787
     
    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")
     
    32153139
    32163140void TV::TogglePIPView(void)
    32173141{
    3218     if (!pipnvp)
     3142    if (!pipplayer && !activenvp->HasPIPPlayer())
    32193143    {
    3220         RemoteEncoder *testrec = RemoteRequestRecorder();
    3221        
    3222         if (!testrec || !testrec->IsValidRecorder())
    3223         {
    3224             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP failed to locate recorder");
    3225             if (testrec)
    3226                 delete testrec;
     3144        int pip_location = gContext->GetNumSetting("PIPLocation", 0);
     3145        QRect rect = activenvp->getVideoOutput()->GetPIPRect(pip_location, NULL);
     3146        pipplayer = PIPPlayer::Create(rect);
     3147        if (!pipplayer)
    32273148            return;
    3228         }
    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         }
     3149        pipplayer->Hide();
     3150        pipplayer->StartPlaying(NULL, true);
     3151        if (pipplayer->IsPlaying())
     3152            pipplayer->Show();
    32453153        else
    32463154        {
    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())
     3155            if (pipplayer->GetNVP() &&
     3156                pipplayer->GetNVP()->PIPSoftwareScaling())
    32623157            {
    3263                 piptvchain->ReloadAll();
    3264                 usleep(5000);
    3265             }
    3266             VERBOSE(VB_PLAYBACK, "PiP NVP Started");
    3267 
    3268             if (pipnvp->IsDecoderThreadAlive())
    3269                 nvp->SetPipPlayer(pipnvp);
     3158                pipplayer->StartPlaying(NULL, true, true);
     3159                if (pipplayer->IsPlaying())
     3160                    activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3161                pipplayerCond.wait();
     3162            }
    32703163            else
    32713164            {
    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();
     3165                delete pipplayer;
     3166                pipplayer = NULL;
    32783167            }
    32793168        }
    3280         else
    3281         {
    3282             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start");
    3283             TeardownPipPlayer();
    3284         }
    32853169    }
    32863170    else
    32873171    {
    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);
     3172        activenvp->SetPIPPlayer(NULL);
     3173        pipplayerCond.wait();
     3174        delete pipplayer;
     3175        pipplayer = NULL;
    33073176    }
    33083177}
    33093178
    33103179void TV::ToggleActiveWindow(void)
    33113180{
    3312     if (!pipnvp)
     3181    // toggleactivewindow works only if the main window is live tv.
     3182    // problem is playbackinfo and internalstate management.
     3183    if (!pipplayer || !pipplayer->IsPlaying() ||
     3184        StateIsPlaying(internalState))
     3185    {
    33133186        return;
    3314 
     3187    }
     3188   
    33153189    lockTimerOn = false;
     3190    LiveTVChain *piptvchain = NULL;
     3191   
    33163192    if (activenvp == nvp)
    33173193    {
    3318         activenvp = pipnvp;
    3319         activerbuffer = piprbuffer;
    3320         activerecorder = piprecorder;
     3194       
     3195        activenvp      = pipplayer->GetNVP();
     3196        activerbuffer  = pipplayer->GetRingBuffer();
     3197        activerecorder = pipplayer->GetRecorder();
     3198        piptvchain     = pipplayer->GetLiveTVChain();
    33213199    }
    33223200    else
    33233201    {
    3324         activenvp = nvp;
    3325         activerbuffer = prbuffer;
     3202        activenvp      = nvp;
     3203        activerbuffer  = prbuffer;
    33263204        activerecorder = recorder;
    33273205    }
    3328     LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    3329     ProgramInfo *pginfo = chain->GetProgramAt(-1);
    3330     if (pginfo)
    3331     {
    3332         SetCurrentlyPlaying(pginfo);
    3333         delete pginfo;
    3334     }
     3206
     3207   if (activerecorder)
     3208   {
     3209        LiveTVChain *chain  = (activenvp == nvp) ? tvchain : piptvchain;
     3210        ProgramInfo *pginfo = chain->GetProgramAt(-1);
     3211        if (pginfo)
     3212        {
     3213            SetCurrentlyPlaying(pginfo);
     3214            delete pginfo;
     3215        }
     3216   }
    33353217}
    33363218
     3219
    33373220struct pip_info
    33383221{
    33393222    RingBuffer    *buffer;
    33403223    RemoteEncoder *recorder;
    33413224    LiveTVChain   *chain;
    33423225    long long      frame;
     3226    ProgramInfo   *pginfo;
    33433227};
    33443228
    33453229void TV::SwapPIP(void)
    33463230{
    3347     if (!pipnvp || !piptvchain || !tvchain)
     3231    if (!pipplayer)
     3232        // TODO print something on OSD informing use that PIP swap cannot be done
    33483233        return;
    33493234
    3350     lockTimerOn = false;
     3235    bool use_nullvideo = pipplayer->UsingNullVideo();
     3236    bool pipislivetv = StateIsLiveTV(internalState);
     3237   
     3238    if (activenvp != nvp)
     3239        ToggleActiveWindow();
    33513240
    3352     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();
     3241    if (paused)
     3242        DoPause();
     3243    StopFFRew();
     3244    NormalSpeed();
    33613245
     3246   if (playbackinfo)
     3247       playbackinfo->setIgnoreBookmark(false);
     3248   if (pipplayer->GetProgramInfo())
     3249       pipplayer->GetProgramInfo()->setIgnoreBookmark(false);
     3250   
     3251   // set the bookmark
     3252    activenvp->SetBookmark();
     3253    pipplayer->GetNVP()->SetBookmark();
     3254   
     3255    struct pip_info main, pip;
     3256    main.buffer      = prbuffer;
     3257    main.recorder    = recorder;
     3258    main.chain       = tvchain;
     3259    main.frame       = nvp->GetFramesPlayed();
     3260    if (StateIsPlaying(internalState))
     3261        main.pginfo = new ProgramInfo(*playbackinfo);
     3262    else
     3263        main.pginfo = NULL;
     3264   
     3265    pip.buffer       = pipplayer->GetRingBuffer();
     3266    pip.recorder     = pipplayer->GetRecorder();
     3267    pip.chain        = pipplayer->GetLiveTVChain();
     3268    pip.frame        = pipplayer->GetNVP()->GetFramesPlayed();
     3269    if (!pipplayer->IsLiveTV())
     3270        pip.pginfo   = new ProgramInfo(*pipplayer->GetProgramInfo());
     3271    else
     3272        pip.pginfo   = NULL;
     3273 
     3274    pipplayer->Hide();
     3275    if (use_nullvideo)
     3276    {
     3277        activenvp->SetPIPPlayer(NULL);
     3278        pipplayerCond.wait();
     3279    }
     3280    pipplayer->SetReinit(false);
     3281    pipplayer->StopPlaying();
     3282   
    33623283    prbuffer->Pause();
    33633284    prbuffer->WaitForPause();
    33643285
    3365     piprbuffer->Pause();
    3366     piprbuffer->WaitForPause();
    3367 
    33683286    nvp->StopPlaying();
    3369     pipnvp->StopPlaying();
     3287
    33703288    {
    3371         QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd...
     3289        QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd..
    33723290        pthread_join(decode, NULL);
    33733291        delete nvp;
    33743292        nvp = NULL;
    3375         pthread_join(pipdecode, NULL);
    3376         delete pipnvp;
    3377         pipnvp = NULL;
    33783293    }
    33793294
     3295    if (playbackinfo)
     3296        delete playbackinfo;
     3297   
    33803298    activerbuffer  = prbuffer = pip.buffer;
    33813299    activerecorder = recorder = pip.recorder;
    33823300    tvchain                   = pip.chain;
     3301    playbackinfo              = pip.pginfo;
     3302    internalState             = GetPIPState(pipplayer);
    33833303
    3384     piprbuffer  = main.buffer;
    3385     piprecorder = main.recorder;
    3386     piptvchain  = main.chain;
    3387 
     3304    pipplayer->SetRingBuffer(main.buffer);
     3305    pipplayer->SetRecorder(main.recorder);
     3306    pipplayer->SetLiveTVChain(main.chain);
     3307    pipplayer->SetProgramInfo(main.pginfo);
     3308   
     3309    VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1")
     3310            .arg(StateToString(internalState)));
     3311   
    33883312    prbuffer->Seek(0, SEEK_SET);
    33893313    prbuffer->Unpause();
    3390     StartPlayer(false);
    3391     activenvp = nvp;
    3392     nvp->FastForward(pip.frame/recorder->GetFrameRate());
    33933314
    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())
     3315    if (internalState == kState_WatchingRecording)
     3316        StartPlayer(true);
     3317    else
     3318        StartPlayer(false);
     3319
     3320    activenvp = nvp;
     3321    usleep(10000);
     3322    if (tvchain)
     3323        nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3324   
     3325    pipplayer->GetRingBuffer()->Seek(0, SEEK_SET);
     3326    pipplayer->GetRingBuffer()->Unpause();
     3327 
     3328    if (use_nullvideo)
    34003329    {
    3401         piptvchain->ReloadAll();
    3402         usleep(5000);
     3330        pipplayer->StartPlaying(main.pginfo, pipislivetv, true);
     3331        if (pipplayer->IsPlaying())
     3332            activenvp->SetPIPPlayer(pipplayer->GetNVP());
    34033333    }
    3404     VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");
    3405     pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());
    3406 
    3407     if (pipnvp->IsDecoderThreadAlive())
    3408         nvp->SetPipPlayer(pipnvp);
    34093334    else
     3335        pipplayer->StartPlaying(main.pginfo, pipislivetv);
     3336
     3337    if (pipplayer->IsPlaying())
    34103338    {
    3411         VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start");
    3412         TeardownPipPlayer();
     3339        if (!use_nullvideo)
     3340            pipplayer->Show();
     3341        if (pipplayer->GetLiveTVChain())
     3342        {
     3343            pipplayer->GetLiveTVChain()->ReloadAll();
     3344            usleep(5000);
     3345        }
    34133346    }
    34143347
    3415     ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
    3416     if (pginfo)
     3348    if (internalState == kState_WatchingLiveTV)
     3349        SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV);
     3350
     3351    if (pipplayer->IsLiveTV())
     3352        SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3353
     3354    if (pipplayer->GetLiveTVChain())
     3355        pipplayer->GetNVP()->FastForward(main.frame/pipplayer->GetRecorder()->GetFrameRate());
     3356
     3357    if (tvchain)
    34173358    {
    3418         SetCurrentlyPlaying(pginfo);
    3419         delete pginfo;
     3359        ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
     3360        if (pginfo)
     3361        {
     3362            SetCurrentlyPlaying(pginfo);
     3363            delete pginfo;
     3364        }
    34203365    }
     3366    pipplayer->SetReinit(true);
    34213367}
    34223368
     3369TVState TV::GetPIPState(PIPPlayer *player)
     3370{
     3371    if (player->IsLiveTV())
     3372        return kState_WatchingLiveTV;
     3373    else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0))
     3374        return kState_WatchingRecording;
     3375    else
     3376        return kState_WatchingPreRecorded;
     3377}
     3378
    34233379void TV::DoPlay(void)
    34243380{
    34253381    float time = 0.0;
     
    34743430    float time = 0.0;
    34753431
    34763432    if (paused)
     3433    {
    34773434        activenvp->Play(normal_speed, true);
     3435        if (pipplayer && pipplayer->IsPlaying())
     3436            pipplayer->GetNVP()->Play(normal_speed, true);
     3437    }
    34783438    else
    34793439    {
    34803440        if (doing_ff_rew)
     
    34853445        }
    34863446       
    34873447        activenvp->Pause();
     3448        if (pipplayer && pipplayer->IsPlaying())
     3449            pipplayer->GetNVP()->Pause();
    34883450    }
    34893451
    34903452    paused = !paused;
     
    38493811
    38503812    RemoteEncoder *testrec = NULL;
    38513813
    3852     if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
     3814    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer)
    38533815        return;
    38543816
    38553817    if (/*chanid || */!channum.isEmpty())
     
    53695331                menurunning = false;
    53705332                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    53715333            }
    5372             else if (piprecorder &&
    5373                      cardnum == piprecorder->GetRecorderNumber())
     5334            else if (pipplayer && pipplayer->GetRecorder() &&
     5335                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53745336            {
    53755337                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
    53765338                TogglePIPView();
     
    53885350                wantsToQuit = false;
    53895351                exitPlayer = true;
    53905352            }
    5391             else if (piprecorder &&
    5392                      cardnum == piprecorder->GetRecorderNumber())
     5353            else if (pipplayer && pipplayer->GetRecorder() &&
     5354                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53935355            {
    53945356                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
    53955357                TogglePIPView();
     
    54055367            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
    54065368
    54075369            if ((recorder    && cardnum == recorder->GetRecorderNumber()) ||
    5408                 (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     5370                (pipplayer && pipplayer->GetRecorder() &&
     5371                 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()))
    54095372            {
    54105373                if (watch)
    54115374                {
     
    54145377                    if (pi.FromStringList(list, 0))
    54155378                        SetPseudoLiveTV(s, &pi, kPseudoChangeChannel);
    54165379
    5417                     if (!s && pipnvp)
     5380                    if (!s && pipplayer)
    54185381                        TogglePIPView();
    54195382                }
    54205383                else
     
    64366399
    64376400    if (StateIsLiveTV(GetState()))
    64386401    {
    6439         bool freeRecorders = (pipnvp != NULL);
     6402        bool freeRecorders = (pipplayer != NULL);
    64406403        if (!freeRecorders)
    64416404            freeRecorders = RemoteGetFreeRecorderCount();
    64426405
     
    70767039{
    70777040    VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()");
    70787041
     7042    LiveTVChain *piptvchain = NULL;
     7043    if (pipplayer)
     7044        piptvchain = pipplayer->GetLiveTVChain();
     7045
    70797046    LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    70807047
    70817048    if (activenvp && chain)
  • libs/libmythtv/videooutbase.cpp

     
    171171    pip_desired_display_size(160,128),  pip_display_size(0,0),
    172172    pip_video_size(0,0),
    173173    pip_tmp_buf(NULL),                  pip_scaling_context(NULL),
     174    piptype(kPIPOff),
    174175
    175176    // Video resizing (for ITV)
    176177    vsz_enabled(false),
     
    253254
    254255    db_vdisp_profile->SetInput(video_dim);
    255256
    256     letterbox  = db_letterbox;
     257    if (piptype == kPIPOff)
     258        letterbox  = db_letterbox;
    257259
    258260    VideoAspectRatioChanged(aspect); // apply aspect ratio and letterbox mode
    259261
     
    10441046
    10451047    db_pict_attr[attributeType] = newValue;
    10461048}
     1049/*
     1050 * \brief Determines PIP Window size and Position.
     1051 */
     1052QRect VideoOutput::GetPIPRect(int location, NuppelVideoPlayer *pipplayer)
     1053{
     1054   
     1055    int tmph;
     1056    int tmpw;
     1057    int letterXadj  = 0;
     1058    int letterYadj  = 0;
     1059    float letterAdj = 1.0f;
     1060    int xpos = 0;
     1061    int ypos = 0;
     1062    int frame_height;
     1063    int frame_width;
     1064   
     1065    if (pipplayer)
     1066    {
     1067        frame_height = video_dim.height();
     1068        frame_width  = video_dim.width();
     1069    }
     1070    else
     1071    {
     1072        frame_height = display_visible_rect.height();
     1073        frame_width  = display_visible_rect.width();
     1074    }
     1075    float pipVideoAspect;
     1076    uint pipVideoWidth;
     1077    uint pipVideoHeight;
     1078   
     1079    if (pipplayer)
     1080    {
     1081        pipVideoAspect = pipplayer->GetVideoAspect();
     1082        pipVideoWidth  = pipplayer->GetVideoWidth();
     1083        pipVideoHeight = pipplayer->GetVideoHeight();
     1084    }
     1085   
     1086    if  (pipplayer && letterbox != kLetterbox_Off)
     1087    {
     1088        letterXadj = max(-display_video_rect.left(), 0);
     1089        float xadj = (float) video_rect.width() / display_visible_rect.width();
     1090        letterXadj = (int) (letterXadj * xadj);
    10471091
     1092        float yadj = (float)video_rect.height() / display_visible_rect.height();
     1093        letterYadj = max(-display_video_rect.top(), 0);
     1094        letterYadj = (int) (letterYadj * yadj);
     1095        if (!pipplayer)
     1096        {
     1097            if (location == kPIPTopLeft || location == kPIPTopRight)
     1098                ypos = display_video_rect.y();
     1099            else
     1100                ypos = -(display_video_rect.y());
     1101        }
     1102       
     1103        letterAdj = video_aspect / letterboxed_video_aspect;
     1104
     1105    }
     1106   
     1107    // set height
     1108    tmph = (frame_height * db_pip_size) / 100;
     1109
     1110    float dispPixelAdj = video_dim.width() / video_dim.height();
     1111   
     1112    tmpw = (int)(tmph * letterAdj * dispPixelAdj);
     1113   
     1114    switch (location)
     1115    {
     1116        default:
     1117        case kPIPTopLeft:
     1118            xpos = 30 + letterXadj;
     1119            ypos += 40 + letterYadj;
     1120            break;
     1121        case kPIPBottomLeft:
     1122            xpos = 30 + letterXadj;
     1123            ypos += frame_height - tmph - 40 - letterYadj;
     1124            break;
     1125        case kPIPTopRight:
     1126            xpos = frame_width  - tmpw - 30 - letterXadj;
     1127            ypos += 40 + letterXadj;
     1128            break;
     1129        case kPIPBottomRight:
     1130            xpos = frame_width  - tmpw - 30 - letterXadj;
     1131            ypos += frame_height - tmph - 40 - letterYadj;
     1132            break;
     1133    }
     1134    return QRect(xpos, ypos, tmpw, tmph);
     1135}
     1136
    10481137/**
    10491138 * \fn VideoOutput::DoPipResize(int,int)
    10501139 * \brief Sets up Picture in Picture image resampler.
     
    11111200    int pipw, piph;
    11121201
    11131202    VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
     1203
    11141204    float pipVideoAspect = pipplayer->GetVideoAspect();
    1115     uint  pipVideoWidth  = pipplayer->GetVideoWidth();
    1116     uint  pipVideoHeight = pipplayer->GetVideoHeight();
    11171205
    11181206    // If PiP is not initialized to values we like, silently ignore the frame.
    11191207    if ((video_aspect <= 0) || (pipVideoAspect <= 0) ||
     
    11231211        pipplayer->ReleaseCurrentFrame(pipimage);
    11241212        return;
    11251213    }
     1214   
     1215    QRect piprect = GetPIPRect(db_pip_location, pipplayer);
    11261216
    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 
     1217    pip_desired_display_size.setWidth((piprect.width() >> 1 ) << 1);
     1218    pip_desired_display_size.setHeight((piprect.height() >> 1) << 1);
     1219   
     1220   
    11601221    // Scale the image if we have to...
    11611222    unsigned char *pipbuf = pipimage->buf;
    11621223    if (pipw != pip_desired_display_size.width() ||
     
    11861247
    11871248
    11881249    // 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     }
     1250    int xoff = piprect.x();
     1251    int yoff = piprect.y();
    12111252
    12121253    // Copy Y (intensity values)
    12131254    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{
     23};
     24
     25PIPPlayer::~PIPPlayer(void)
     26{
     27    StopPlaying();
     28    if (pipWindow)
     29        pipWindow->deleteLater();
     30};
     31
     32PIPPlayer * PIPPlayer::Create(NuppelVideoPlayer *parentnvp, int location)
     33{
     34    PIPPlayer *tmppip = new PIPPlayer();
     35    if (parentnvp)
     36    {
     37        QRect rect = parentnvp->getVideoOutput()->GetPIPRect(location, NULL);
     38        tmppip->Init(rect, QString("pip player %1").arg((int)location));
     39        return tmppip;
     40    }
     41    delete tmppip;
     42    return NULL;
     43}
     44
     45PIPPlayer * PIPPlayer::Create(const QRect &rect)
     46{
     47    PIPPlayer *tmppip = new PIPPlayer();
     48    tmppip->Init(rect, "pip player");
     49    return tmppip;
     50}
     51
     52void PIPPlayer::Init(QRect rect, QString name)
     53{
     54    QRect piprect = QRect(rect);
     55    MythDialog *window = new MythDialog(gContext->GetMainWindow(), name);
     56    window->setNoErase();
     57    window->setGeometry(piprect);
     58    window->setFixedSize(piprect.size());
     59    window->show();
     60    window->setBackgroundColor(Qt::black);
     61    gContext->GetMainWindow()->detach(window);
     62    pipWindow = window;
     63}
     64
     65void PIPPlayer::Reinitialize(void)
     66{
     67    if (pipnvp)
     68        delete pipnvp;
     69
     70    pipnvp = NULL;
     71   
     72    if (piprbuffer)
     73        delete piprbuffer;
     74    piprbuffer = NULL;
     75   
     76    if (piprecinfo)
     77        delete piprecinfo;
     78    piprecinfo = NULL;
     79   
     80    if (piprecorder)
     81        delete piprecorder;
     82    piprecorder = NULL;
     83   
     84    if (piptvchain)
     85    {
     86        piptvchain->DestroyChain();
     87        delete piptvchain;
     88    }
     89    piptvchain = NULL;
     90}
     91
     92/*
     93 * \brief Setup pip and start playing it.
     94 * \param piptype: set to true, if pip should open a tuner
     95 * \returns true if setup is complete
     96 */
     97bool PIPPlayer::StartPlaying(ProgramInfo *rec, bool piptype, bool nullvideo)
     98{
     99
     100    using_nullvideo = nullvideo;
     101    islivetv = piptype;
     102 
     103    if (reinit)
     104        Reinitialize();
     105
     106    RemoteEncoder *testrec = NULL;
     107   
     108    VERBOSE(VB_PLAYBACK, LOC +
     109            QString("PIP is for %1").arg((islivetv) ? "live tv":"a recording"));
     110
     111    if (islivetv)
     112    {
     113        if (!(piprecorder && piprbuffer && piptvchain))
     114        {
     115            testrec = RemoteRequestRecorder();
     116
     117            if (!testrec || !testrec->IsValidRecorder())
     118            {
     119                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP failed to locate recorder");
     120                if (testrec)
     121                    delete testrec;
     122                return false;
     123            }
     124
     125            testrec->Setup();
     126
     127            piptvchain = new LiveTVChain();
     128            piptvchain->InitializeNewChain("PIP"+gContext->GetHostName());
     129            testrec->SpawnLiveTV(piptvchain->GetID(), true);
     130            piptvchain->ReloadAll();
     131            piprecinfo = piptvchain->GetProgramAt(-1);
     132            if (!piprecinfo)
     133            {
     134                VERBOSE(VB_IMPORTANT, LOC_ERR +
     135                        "PIP cannot find live tv programinfo. Exiting");
     136                delete testrec;
     137                piptvchain->DestroyChain();
     138                delete piptvchain;
     139                return false;
     140            }
     141            else
     142            {
     143                QString playbackURL = piprecinfo->GetPlaybackURL();
     144                piptvchain->SetProgram(piprecinfo);
     145                piprbuffer = new RingBuffer(playbackURL, false);
     146                piprbuffer->SetLiveMode(piptvchain);
     147            }
     148
     149            piprecorder = testrec;
     150       
     151            if (!StartRecorder(piprecorder, -1))
     152            {
     153                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP recorder failed to start");
     154                return false;
     155            }
     156        }
     157    }
     158    else // pip is not Live TV
     159    {
     160        if (!piprecinfo)
     161            piprecinfo = new ProgramInfo(*rec);
     162        if (!piprbuffer)
     163            piprbuffer = new RingBuffer(piprecinfo->pathname, false, false, 1);
     164        if (!piprbuffer->IsOpen())
     165        {
     166            VERBOSE(VB_IMPORTANT, LOC_ERR +
     167                QString("Failed to open Ringbuffer %1")
     168                .arg(piprecinfo->pathname));
     169            return false;
     170        }
     171    }
     172
     173    // when starting pipplayer for the first time, always start
     174    // from the beginning
     175    if (reinit && piprecinfo)
     176        piprecinfo->setIgnoreBookmark(true);
     177       
     178    pipnvp = new NuppelVideoPlayer("pip player", piprecinfo);
     179    pipnvp->SetParentWidget(pipWindow);
     180    pipnvp->SetRingBuffer(piprbuffer);
     181    if (islivetv)
     182    {
     183        pipnvp->SetRecorder(piprecorder);
     184        pipnvp->SetLiveTVChain(piptvchain);
     185    }
     186    else
     187        pipnvp->SetLength(piprecinfo->CalculateLength());
     188       
     189
     190    // setAsPIP is true if null video output is used
     191    // PIP will be embedded in XV
     192    if (using_nullvideo)
     193    {
     194        pipnvp->SetAsPIP(true);
     195    }
     196    else
     197        pipnvp->SetAsPIP(false);
     198
     199    VERBOSE(VB_PLAYBACK, "PIP Waiting for NVP");
     200    pthread_create(&pipdecode, NULL, SpawnPIPVideoThread, pipnvp);
     201    int maxWait = 20000;
     202    MythTimer t;
     203    t.start();
     204    while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive() &&
     205            t.elapsed() < maxWait)
     206    {
     207        usleep(5000);
     208    }
     209   
     210    if (!pipnvp->IsPlaying())
     211    {
     212        VERBOSE(VB_PLAYBACK, LOC_ERR + "PIP NVP Failed to Start");
     213        return false;
     214    }
     215   
     216    VERBOSE(VB_PLAYBACK, LOC + "PIP NVP Started");
     217    return true;
     218}
     219
     220void PIPPlayer::StopPlaying(void)
     221{
     222   
     223    if (!pipnvp)
     224        return;
     225
     226    if (pipnvp->IsPlaying())
     227    {
     228        if (reinit)
     229            piprbuffer->StopReads();
     230        piprbuffer->Pause();
     231        piprbuffer->WaitForPause();
     232        pipnvp->StopPlaying();
     233    }
     234   
     235    VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): Stopped Playing");
     236    {
     237        pthread_join(pipdecode, NULL);
     238        delete pipnvp;
     239        pipnvp = NULL;
     240    }
     241
     242    if (reinit)
     243    {
     244        if (islivetv && piprecorder )
     245            piprecorder->StopLiveTV();
     246   
     247        Reinitialize();
     248    }
     249   
     250    VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): NVP deleted");
     251}
     252
     253/*
     254 * \brief set pip ringbuffer if pip is not playing
     255 */
     256void PIPPlayer::SetRingBuffer(RingBuffer *rbuffer)
     257{
     258    if (!IsPlaying())
     259        piprbuffer = rbuffer;
     260}
     261
     262/*
     263 * \brief set pip tvchain if pip is not playing
     264 */
     265void PIPPlayer::SetLiveTVChain(LiveTVChain *tvchain)
     266{
     267    if (!IsPlaying())
     268        piptvchain = tvchain;
     269}
     270
     271/*
     272 * \brief set pip recorder if pip is not playing
     273 */
     274void PIPPlayer::SetRecorder(RemoteEncoder  *recorder)
     275{
     276    if (!IsPlaying())
     277        piprecorder = recorder;
     278}
     279
     280void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo)
     281{
     282    if (!IsPlaying())
     283    {
     284        if (piprecinfo)
     285            delete piprecinfo;
     286        piprecinfo = pginfo;
     287    }
     288}
     289
     290bool PIPPlayer::IsSameProgram(ProgramInfo *rec)
     291{
     292    if (!rec || !piprecinfo)
     293        return false;
     294
     295    if (piprecinfo->IsSameProgram(*rec))
     296        return true;
     297   
     298    return false;
     299}
     300
     301bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait)
     302{
     303    maxWait = (maxWait <= 0) ? 40000 : maxWait;
     304    MythTimer t;
     305    t.start();
     306    while (rec && !rec->IsRecording() && t.elapsed() < maxWait)
     307        usleep(5000);
     308    if (rec && !rec->IsRecording())
     309    {
     310        VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out");
     311        return false;
     312    }
     313    return true;
     314}
     315
     316void PIPPlayer::Hide(void)
     317{
     318    if (pipWindow && pipWindow->isVisible())
     319        pipWindow->hide();
     320}
     321
     322void PIPPlayer::Show(void)
     323{   
     324    if (pipWindow && pipWindow->isHidden())
     325        pipWindow->show();
     326}
     327
     328bool PIPPlayer::IsHidden(void)
     329{
     330    if (pipWindow && pipWindow->isHidden())
     331        return true;
     332    return false;
     333}
     334
     335void PIPPlayer::DisplaySoftwareScaledImage(void)
     336{
     337    if (!using_nullvideo)
     338        return;
     339   
     340    QPainter p(pipWindow);
     341    QSize size = pipWindow->size();
     342    float saspect = ((float)size.width())/ ((float)size.height());
     343    float vaspect = pipnvp->GetVideoAspect();
     344    size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
     345    size.setHeight(((size.height() + 7) / 8) * 8);
     346    size.setWidth( ((size.width()  + 7) / 8) * 8);
     347    const QImage &img = pipnvp->GetARGBFrame(size);
     348    p.drawImage(0, 0, img);
     349}
  • 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);
    9395
  • libs/libmythtv/videoout_xv.cpp

     
    12181218        db_vdisp_profile->SetVideoRenderer(renderer);
    12191219    }
    12201220
     1221    const QString osdrenderer = db_vdisp_profile->GetOSDRenderer();
     1222    if (piptype == kPIPOnTV  &&
     1223            (osdrenderer != "opengl" || osdrenderer != "composite"))
     1224    {
     1225        VERBOSE(VB_IMPORTANT, LOC + QString("XV PIP not supported with blended OSD. "
     1226                    "Using software scaled PIP."));
     1227        return false;
     1228    }
    12211229    // Initialize the OSD, if we need to
    1222     InitOSD(db_vdisp_profile->GetOSDRenderer());
     1230    if (piptype == kPIPOff)
     1231        InitOSD(osdrenderer);
    12231232
    12241233    // Create video buffers
    12251234    bool use_xv  = (renderer.left(2) == "xv");
     
    12591268{
    12601269    needrepaint = true;
    12611270
     1271    // for PIP use software scaled image if width or height <= 64
     1272    if (piptype > kPIPOff &&
     1273        (width <= 64 || height <= 64))
     1274        return false;
     1275       
    12621276    XV_INIT_FATAL_ERROR_TEST(winid <= 0, "Invalid Window ID.");
    12631277
    12641278    XJ_disp = MythXOpenDisplay();
  • libs/libmythtv/videooutbase.h

     
    7979    kPIPBottomRight
    8080};
    8181
     82enum PIPType
     83{
     84    kPIPOff = 0,
     85    kPIPOn, // PIP but not for TV
     86    kPIPOnTV // PIP used in TV mode
     87};
     88
    8289enum ZoomDirections
    8390{
    8491    kZoomHome = 0,
     
    225232    bool AllowPreviewEPG(void) { return allowpreviewepg; }
    226233
    227234    /// \brief Returns true iff Motion Compensation acceleration is available.
    228     virtual bool hasMCAcceleration() const { return false; }
     235    virtual bool hasMCAcceleration(void) const { return false; }
    229236    /// \brief Returns true iff Inverse Discrete Cosine Transform acceleration
    230237    ///        is available.
    231     virtual bool hasIDCTAcceleration() const { return false; }
     238    virtual bool hasIDCTAcceleration(void) const { return false; }
    232239    /// \brief Returns true iff VLD acceleration is available.
    233     virtual bool hasVLDAcceleration() const { return false; }
     240    virtual bool hasVLDAcceleration(void) const { return false; }
     241    /// \brief Returns true if XV or XVMC is available
     242    virtual bool hasXVAcceleration(void) const { return false; }
    234243
    235244    /// \brief Sets the number of frames played
    236245    virtual void SetFramesPlayed(long long fp) { framesPlayed = fp; };
     
    308317    /// \brief Tells the player to resize the video frame (used for ITV)
    309318    void SetVideoResize(const QRect &videoRect);
    310319
     320    /// \brief returns QRect of PIP based on PIPLocation
     321    virtual QRect GetPIPRect(int location, NuppelVideoPlayer *pipplayer = NULL);
     322
     323    /// set PIP Type
     324    void SetAsPIP(PIPType setting) { piptype = setting; }
     325       
     326
    311327  protected:
    312328    void InitBuffers(int numdecode, bool extra_for_pause, int need_free,
    313329                     int needprebuffer_normal, int needprebuffer_small,
     
    384400    QSize   pip_video_size;
    385401    unsigned char      *pip_tmp_buf;
    386402    ImgReSampleContext *pip_scaling_context;
     403    PIPType    piptype;
    387404
    388405    // Video resizing (for ITV)
    389406    bool    vsz_enabled;
  • programs/mythfrontend/playbackbox.cpp

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

     
    18391839    return gc;
    18401840}
    18411841
    1842 static HostCheckBox *PlaybackPreviewLowCPU()
    1843 {
    1844     HostCheckBox *gc = new HostCheckBox("PlaybackPreviewLowCPU");
    1845     gc->setLabel(QObject::tr("CPU friendly preview of recordings"));
    1846     gc->setValue(false);
    1847     gc->setHelpText(QObject::tr("When enabled, recording previews "
    1848                     "will play with reduced FPS to save CPU."));
    1849     return gc;
    1850 }
    1851 
    18521842static HostCheckBox *PlayBoxTransparency()
    18531843{
    18541844    HostCheckBox *gc = new HostCheckBox("PlayBoxTransparency");
     
    41874177    pbox->addChild(PreviewPixmapOffset());
    41884178    pbox->addChild(PreviewFromBookmark());
    41894179    pbox->addChild(PlaybackPreview());
    4190     pbox->addChild(PlaybackPreviewLowCPU());
    41914180    pbox->addChild(PBBStartInTitle());
    41924181    pbox->addChild(PBBShowGroupSummary());
    41934182    addChild(pbox);
  • programs/mythfrontend/playbackbox.h

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