Ticket #843: pipplayer.4.diff

File pipplayer.4.diff, 77.3 KB (added by skamithi, 13 years ago)

some bug fixes. still have to fix tv:swappip and tv::toggleactivewindow.. also need to check main xvideo surface if it can support the pip.

  • 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)")
     
    25892607        {
    25902608            pipplayer = setpipplayer;
    25912609            needsetpipplayer = false;
     2610            if (m_tv)
     2611                m_tv->PIPPlayerWake();
    25922612        }
    25932613
    25942614        if (ringBuffer->isDVD())
     
    30493069
    30503070    if (!InitVideo())
    30513071    {
    3052         qApp->lock();
    3053         DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
     3072        if (!ispip)
     3073        {
     3074            qApp->lock();
     3075            DialogBox *dialog = new DialogBox(gContext->GetMainWindow(),
    30543076                                   QObject::tr("Unable to initialize video."));
    3055         dialog->AddButton(QObject::tr("Return to menu."));
    3056         dialog->exec();
    3057         delete dialog;
     3077            dialog->AddButton(QObject::tr("Return to menu."));
     3078            dialog->exec();
     3079            delete dialog;
     3080            qApp->unlock();
     3081        }
    30583082
    3059         qApp->unlock();
    3060 
    30613083        if (audioOutput)
    30623084        {
    30633085            delete audioOutput;
     
    36563678    int numFrames = totalFrames;
    36573679
    36583680    if (m_playbackinfo->GetTranscodedStatus() != TRANSCODING_COMPLETE)
    3659         numFrames = (m_playbackinfo->endts.toTime_t() -
    3660                     m_playbackinfo->recstartts.toTime_t()) * video_frame_rate;
     3681        numFrames = (int)((m_playbackinfo->endts.toTime_t() -
     3682                    m_playbackinfo->recstartts.toTime_t()) * video_frame_rate);
    36613683
    36623684    int offset = (int) round(0.14 * (numFrames / video_frame_rate));
    36633685
  • 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.
     
    193194    void SleepEndTimer(void);
    194195    void TreeMenuEntered(OSDListTreeType *tree, OSDGenericTree *item);
    195196    void TreeMenuSelected(OSDListTreeType *tree, OSDGenericTree *item);
     197    void PIPVideoTimer(void);
    196198
    197199  protected:
    198200    void doEditSchedule(int editType = kScheduleProgramGuide);
     
    320322
    321323    void SetupPlayer(bool isWatchingRecording);
    322324    void TeardownPlayer(void);
    323     void SetupPipPlayer(void);
    324     void TeardownPipPlayer(void);
    325325   
    326326    void HandleStateChange(void);
    327327    bool InStateChange(void) const;
     
    331331    void TogglePIPView(void);
    332332    void ToggleActiveWindow(void);
    333333    void SwapPIP(void);
     334    TVState GetPIPState(PIPPlayer *pip);
    334335    void SwapPIPSoon(void) { needToSwapPIP = true; }
    335 
     336   
    336337    void ToggleAutoExpire(void);
    337338
    338339    void BrowseStart(void);
     
    529530
    530531    // Video Players
    531532    NuppelVideoPlayer *nvp;
    532     NuppelVideoPlayer *pipnvp;
     533    PIPPlayer  *pipplayer;
    533534    NuppelVideoPlayer *activenvp;  ///< Player to which LiveTV events are sent
    534535
     536    //PIP Stuff
     537    QTimer *pipVideoTimer;
     538    QWaitCondition pipplayerCond;
     539
    535540    // Remote Encoders
    536541    /// Main recorder
    537542    RemoteEncoder *recorder;
    538     /// Picture-in-Picture recorder
    539     RemoteEncoder *piprecorder;
    540543    /// Recorder to which LiveTV events are being sent
    541544    RemoteEncoder *activerecorder;
    542545    /// Main recorder to use after a successful SwitchCards() call.
     
    546549
    547550    // LiveTVChain
    548551    LiveTVChain *tvchain;
    549     LiveTVChain *piptvchain;
    550552    QStringList tvchainUpdate;
    551553    QMutex tvchainUpdateLock;
    552554
    553555    // RingBuffers
    554556    RingBuffer *prbuffer;
    555     RingBuffer *piprbuffer;
    556557    RingBuffer *activerbuffer; ///< Ringbuffer to which LiveTV events are sent
    557558
    558559    // OSD info
     
    589590    pthread_t event;
    590591    /// Video decoder thread, runs nvp's NuppelVideoPlayer::StartPlaying().
    591592    pthread_t decode;
    592     /// Picture-in-Picture video decoder thread,
    593     /// runs pipnvp's NuppelVideoPlayer::StartPlaying().
    594     pthread_t pipdecode;
    595593
    596594    /// Condition to signal that the Event thread is up and running
    597595    QWaitCondition mainLoopCond;
  • libs/libmythtv/pipplayer.h

     
     1#ifndef PIPPLAYER_H
     2#define PIPPLAYER_H
     3
     4#include <qpainter.h>
     5#include "NuppelVideoPlayer.h"
     6#include "RingBuffer.h"
     7#include "programinfo.h"
     8#include "livetvchain.h"
     9#include "remoteencoder.h"
     10
     11class RingBuffer;
     12class ProgramInfo;
     13class LiveTVChain;
     14class RemoteEncoder;
     15class NuppelVideoPlayer;
     16
     17class PIPPlayer
     18{
     19    public:
     20        PIPPlayer(void);
     21        ~PIPPlayer(void);
     22        static PIPPlayer *Create(const QRect &rect);
     23        static PIPPlayer * Create(NuppelVideoPlayer *parentnvp, int location);
     24        bool StartPlaying(ProgramInfo *rec = NULL,
     25                            bool piptype = false,
     26                            bool nullvideo = false);
     27        void StopPlaying();
     28        bool IsPlaying(void) { return (pipnvp && pipnvp->IsPlaying()); }
     29        void SetFrameRate(double fps);
     30        bool IsSameProgram(ProgramInfo *rec);
     31        RingBuffer          *GetRingBuffer(void) { return piprbuffer; }
     32        RemoteEncoder       *GetRecorder(void) { return piprecorder; }
     33        LiveTVChain         *GetLiveTVChain(void) { return piptvchain; }
     34        NuppelVideoPlayer   *GetNVP(void) { return pipnvp; }
     35        ProgramInfo         *GetProgramInfo(void) { return piprecinfo; }
     36        void SetRingBuffer(RingBuffer *rbuffer);
     37        void SetLiveTVChain(LiveTVChain *tvchain);
     38        void SetRecorder(RemoteEncoder  *recorder);
     39        void SetProgramInfo(ProgramInfo *pginfo);
     40        void SetReinit(bool change) { reinit = change; }
     41        bool IsLiveTV(void) { return islivetv; }
     42        bool IsHidden(void);
     43        void Hide(void);
     44        void Show(void);
     45        bool UsingNullVideo(void) { return using_nullvideo; }
     46        void DisplaySoftwareScaledImage(void);
     47       
     48
     49    private:
     50        bool StartRecorder(RemoteEncoder *rec, int maxWait);
     51        void Reinitialize(void);
     52        void Init(QRect rect, QString name);
     53
     54    private:
     55        RemoteEncoder *piprecorder;
     56        RingBuffer *piprbuffer;
     57        LiveTVChain  *piptvchain;
     58        ProgramInfo *piprecinfo;
     59        NuppelVideoPlayer *pipnvp;
     60        pthread_t videoThread;
     61        pthread_t pipdecode;
     62        QWidget *pipWindow;
     63        bool islivetv;
     64        bool reinit;
     65        bool using_nullvideo;
     66};
     67
     68#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),
     467      // PIP Stuff
     468      pipVideoTimer(new QTimer(this)),
    466469      // Remote Encoders
    467       recorder(NULL), piprecorder(NULL), activerecorder(NULL),
     470      recorder(NULL), activerecorder(NULL),
    468471      switchToRec(NULL), lastrecordernum(-1),
    469472      // LiveTVChain
    470       tvchain(NULL), piptvchain(NULL),
     473      tvchain(NULL),
    471474      // RingBuffers
    472       prbuffer(NULL), piprbuffer(NULL), activerbuffer(NULL),
     475      prbuffer(NULL), activerbuffer(NULL),
    473476      // OSD info
    474477      dialogname(""), treeMenu(NULL), udpnotify(NULL), osdlock(true),
    475478      // LCD Info
     
    502505    connect(muteTimer,        SIGNAL(timeout()), SLOT(UnMute()));
    503506    connect(keyrepeatTimer,   SIGNAL(timeout()), SLOT(KeyRepeatOK()));
    504507    connect(sleepTimer,       SIGNAL(timeout()), SLOT(SleepEndTimer()));
     508    connect(pipVideoTimer,    SIGNAL(timeout()), SLOT(PIPVideoTimer()));
    505509}
    506510
    507511/** \fn TV::Init(bool)
     
    679683        delete tvchain;
    680684    }
    681685
    682     if (piptvchain)
    683     {
    684         VERBOSE(VB_IMPORTANT, LOC + "Deleting PiP TV Chain in destructor");
    685         piptvchain->DestroyChain();
    686         delete piptvchain;
    687     }   
    688 
    689686    if (ddMapLoaderRunning)
    690687    {
    691688        pthread_join(ddMapLoader, NULL);
     
    699696            pthread_detach(ddMapLoader);
    700697        }
    701698    }
     699
     700    if (pipVideoTimer)
     701    {
     702        pipVideoTimer->disconnect(this);
     703        pipVideoTimer->deleteLater();
     704        pipVideoTimer = NULL;
     705    }
     706       
    702707}
    703708
    704709TVState TV::GetState(void) const
     
    13791384            prbuffer->Pause();
    13801385            prbuffer->WaitForPause();
    13811386        }
    1382 
    1383         if (piprbuffer)
    1384         {
    1385             piprbuffer->StopReads();
    1386             piprbuffer->Pause();
    1387             piprbuffer->WaitForPause();
    1388         }
    13891387    }
    13901388
    13911389    if (stopPlayers)
     
    13931391        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (1/2)");
    13941392        if (nvp)
    13951393            nvp->StopPlaying();
    1396 
    1397         if (pipnvp)
    1398             pipnvp->StopPlaying();
    13991394    }
    14001395
    14011396    if (stopRecorders)
     
    14031398        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping recorder[s]");
    14041399        if (recorder)
    14051400            recorder->StopLiveTV();
    1406 
    1407         if (piprecorder)
    1408             piprecorder->StopLiveTV();
    14091401    }
    14101402
    14111403    if (stopPlayers)
     
    14131405        VERBOSE(VB_PLAYBACK, LOC + "StopStuff(): stopping player[s] (2/2)");
    14141406        if (nvp)
    14151407            TeardownPlayer();
    1416 
    1417         if (pipnvp)
    1418             TeardownPipPlayer();
     1408        if (pipplayer)
     1409        {
     1410            delete pipplayer;
     1411            pipplayer = NULL;
     1412        }
    14191413    }
    14201414    VERBOSE(VB_PLAYBACK, LOC + "StopStuff() -- end");
    14211415}
     
    14971491    return filters;
    14981492}
    14991493
    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 
    15221494void TV::TeardownPlayer(void)
    15231495{
    15241496    if (nvp)
     
    15681540        prbuffer = activerbuffer = NULL;
    15691541    }
    15701542
    1571     if (piprbuffer)
    1572     {
    1573         delete piprbuffer;
    1574         piprbuffer = NULL;
    1575     }
    1576 
    15771543    if (tvchain)
    15781544    {
    15791545        tvchain->DestroyChain();
     
    15821548    }
    15831549}
    15841550
    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 
    16241551void *TV::EventThread(void *param)
    16251552{
    16261553    TV *thetv = (TV *)param;
     
    16861613                        if (nvp->GetTVChain())
    16871614                            nvp->CheckTVChain();
    16881615                    }
    1689                     if (piptvchain && pipnvp && *it == piptvchain->GetID())
     1616                    if (pipplayer && pipplayer->IsLiveTV()
     1617                            && *it == pipplayer->GetLiveTVChain()->GetID())
    16901618                    {
     1619                        LiveTVChain *piptvchain = pipplayer->GetLiveTVChain();
    16911620                        piptvchain->ReloadAll();
    1692                         if (pipnvp->GetTVChain())
    1693                             pipnvp->CheckTVChain();
     1621                        if (pipplayer->GetNVP()->GetTVChain())
     1622                            pipplayer->GetNVP()->CheckTVChain();
    16941623                    }
    16951624                }
    16961625                tvchainUpdate.clear();
     
    17521681            wantsToQuit = true;
    17531682        }
    17541683
     1684        if (pipplayer && !pipplayer->IsPlaying())
     1685            TogglePIPView();
     1686
    17551687        if (StateIsPlaying(internalState))
    17561688        {
    17571689#ifdef USING_VALGRIND
     
    18591791            prevChan = tmp;
    18601792            pseudoLiveTVState[i] = kPseudoRecording;
    18611793
    1862             if (i && pipnvp)
     1794            if (i && pipplayer)
    18631795                TogglePIPView();
    18641796        }
    18651797
     
    19761908        {
    19771909            if (nvp)
    19781910                nvp->ExposeEvent();
     1911            if (pipplayer && pipplayer->GetNVP())
     1912                pipplayer->GetNVP()->ExposeEvent();
    19791913            return true;
    19801914        }
    19811915        case MythEvent::MythEventMessage:
     
    25582492            DoQueueTranscode("Low Quality");
    25592493        else if (action == "PLAY")
    25602494            DoPlay();
     2495        else if (action == "TOGGLEPIPMODE")
     2496            TogglePIPView();
     2497        else if (action == "TOGGLEPIPWINDOW")
     2498            ToggleActiveWindow();
     2499        else if (action == "SWAPPIP")
     2500            SwapPIPSoon();
    25612501        else if (action == "PAUSE")
    25622502            DoPause();
    25632503        else if (action == "SPEEDINC" && !activerbuffer->InDVDMenuOrStillFrame())
     
    29262866                SwitchCards();
    29272867            else if (action == "GUIDE")
    29282868                EditSchedule(kScheduleProgramGuide);
    2929             else if (action == "TOGGLEPIPMODE")
    2930                 TogglePIPView();
    2931             else if (action == "TOGGLEPIPWINDOW")
    2932                 ToggleActiveWindow();
    2933             else if (action == "SWAPPIP")
    2934                 SwapPIPSoon();
    29352869            else if (action == "TOGGLEBROWSE")
    29362870                BrowseStart();
    29372871            else if (action == "PREVCHAN")
     
    32133147    }
    32143148}
    32153149
     3150void TV::PIPVideoTimer(void)
     3151{
     3152    if (pipplayer && pipplayer->IsPlaying())
     3153        pipplayer->SetFrameRate(10.0);
     3154}
     3155
    32163156void TV::TogglePIPView(void)
    32173157{
    3218     if (!pipnvp)
     3158    if (!pipplayer && !activenvp->HasPIPPlayer())
    32193159    {
    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;
     3160        int pip_location = gContext->GetNumSetting("PIPLocation", 0);
     3161        QRect rect = activenvp->getVideoOutput()->GetPIPRect(pip_location);
     3162        pipplayer = PIPPlayer::Create(rect);
     3163        if (!pipplayer)
    32273164            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         }
     3165        pipplayer->Hide();
     3166        pipplayer->StartPlaying(NULL, true);
     3167        if (pipplayer->IsPlaying())
     3168            pipplayer->Show();
    32453169        else
    32463170        {
    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())
     3171            if (pipplayer->GetNVP() &&
     3172                pipplayer->GetNVP()->PIPSoftwareScaling())
    32623173            {
    3263                 piptvchain->ReloadAll();
    3264                 usleep(5000);
    3265             }
    3266             VERBOSE(VB_PLAYBACK, "PiP NVP Started");
    3267 
    3268             if (pipnvp->IsDecoderThreadAlive())
    3269                 nvp->SetPipPlayer(pipnvp);
     3174                pipplayer->StartPlaying(NULL, true, true);
     3175                if (pipplayer->IsPlaying())
     3176                    activenvp->SetPIPPlayer(pipplayer->GetNVP());
     3177                pipplayerCond.wait();
     3178                pipVideoTimer->start(2000);
     3179            }
    32703180            else
    32713181            {
    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();
     3182                delete pipplayer;
     3183                pipplayer = NULL;
    32783184            }
    32793185        }
    3280         else
    3281         {
    3282             VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP recorder failed to start");
    3283             TeardownPipPlayer();
    3284         }
    32853186    }
    32863187    else
    32873188    {
    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);
     3189        activenvp->SetPIPPlayer(NULL);
     3190        pipplayerCond.wait();
     3191        delete pipplayer;
     3192        pipplayer = NULL;
     3193        pipVideoTimer->stop();
    33073194    }
    33083195}
    33093196
    33103197void TV::ToggleActiveWindow(void)
    33113198{
    3312     if (!pipnvp)
    3313         return;
     3199    /* its broken. needs more work. need to keep track of the
     3200     * different programinfos for each nvp
     3201     * working on it
     3202     */
     3203   /*
     3204   if (!pipplayer || !pipplayer->IsPlaying())
     3205       return;
     3206   
     3207   lockTimerOn = false;
     3208   LiveTVChain *piptvchain = NULL;
     3209   
     3210   if (activenvp == nvp)
     3211   {
     3212       
     3213       activenvp      = pipplayer->GetNVP();
     3214       activerbuffer  = pipplayer->GetRingBuffer();
     3215       activerecorder = pipplayer->GetRecorder();
     3216       piptvchain     = pipplayer->GetLiveTVChain();
     3217   }
     3218   else
     3219   {
     3220       activenvp      = nvp;
     3221       activerbuffer  = prbuffer;
     3222       activerecorder = recorder;
     3223   }
    33143224
    3315     lockTimerOn = false;
    3316     if (activenvp == nvp)
    3317     {
    3318         activenvp = pipnvp;
    3319         activerbuffer = piprbuffer;
    3320         activerecorder = piprecorder;
    3321     }
    3322     else
    3323     {
    3324         activenvp = nvp;
    3325         activerbuffer = prbuffer;
    3326         activerecorder = recorder;
    3327     }
    3328     LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    3329     ProgramInfo *pginfo = chain->GetProgramAt(-1);
    3330     if (pginfo)
    3331     {
    3332         SetCurrentlyPlaying(pginfo);
    3333         delete pginfo;
    3334     }
     3225   if (activerecorder)
     3226   {
     3227        LiveTVChain *chain  = (activenvp == nvp) ? tvchain : piptvchain;
     3228        ProgramInfo *pginfo = chain->GetProgramAt(-1);
     3229        if (pginfo)
     3230        {
     3231            SetCurrentlyPlaying(pginfo);
     3232            delete pginfo;
     3233        }
     3234   }
     3235
     3236   */
    33353237}
    33363238
     3239
    33373240struct pip_info
    33383241{
    33393242    RingBuffer    *buffer;
    33403243    RemoteEncoder *recorder;
    33413244    LiveTVChain   *chain;
    33423245    long long      frame;
     3246    ProgramInfo   *pginfo;
    33433247};
    33443248
    33453249void TV::SwapPIP(void)
    33463250{
    3347     if (!pipnvp || !piptvchain || !tvchain)
     3251    if (!pipplayer)
     3252        // TODO print something on OSD informing use that PIP swap cannot be done
    33483253        return;
    33493254
    3350     lockTimerOn = false;
     3255    bool use_nullvideo = pipplayer->UsingNullVideo();
     3256    bool pipislivetv = StateIsLiveTV(internalState);
     3257   
     3258    if (activenvp != nvp)
     3259        ToggleActiveWindow();
    33513260
    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();
     3261    if (paused)
     3262        DoPause();
     3263    StopFFRew();
     3264    NormalSpeed();
    33613265
     3266   if (playbackinfo)
     3267       playbackinfo->setIgnoreBookmark(false);
     3268   if (pipplayer->GetProgramInfo())
     3269       pipplayer->GetProgramInfo()->setIgnoreBookmark(false);
     3270   
     3271   // set the bookmark
     3272    activenvp->SetBookmark();
     3273    pipplayer->GetNVP()->SetBookmark();
     3274   
     3275    struct pip_info main, pip;
     3276    main.buffer      = prbuffer;
     3277    main.recorder    = recorder;
     3278    main.chain       = tvchain;
     3279    main.frame       = nvp->GetFramesPlayed();
     3280    if (StateIsPlaying(internalState))
     3281        main.pginfo = new ProgramInfo(*playbackinfo);
     3282    else
     3283        main.pginfo = NULL;
     3284   
     3285    pip.buffer       = pipplayer->GetRingBuffer();
     3286    pip.recorder     = pipplayer->GetRecorder();
     3287    pip.chain        = pipplayer->GetLiveTVChain();
     3288    pip.frame        = pipplayer->GetNVP()->GetFramesPlayed();
     3289    if (!pipplayer->IsLiveTV())
     3290        pip.pginfo   = new ProgramInfo(*pipplayer->GetProgramInfo());
     3291    else
     3292        pip.pginfo   = NULL;
     3293 
     3294    pipplayer->Hide();
     3295    if (use_nullvideo)
     3296    {
     3297        activenvp->SetPIPPlayer(NULL);
     3298        pipplayerCond.wait();
     3299    }
     3300    pipplayer->SetReinit(false);
     3301    pipplayer->StopPlaying();
     3302   
    33623303    prbuffer->Pause();
    33633304    prbuffer->WaitForPause();
    33643305
    3365     piprbuffer->Pause();
    3366     piprbuffer->WaitForPause();
    3367 
    33683306    nvp->StopPlaying();
    3369     pipnvp->StopPlaying();
     3307
    33703308    {
    3371         QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd...
     3309        QMutexLocker locker(&osdlock); // prevent UpdateOSDSignal using osd..
    33723310        pthread_join(decode, NULL);
    33733311        delete nvp;
    33743312        nvp = NULL;
    3375         pthread_join(pipdecode, NULL);
    3376         delete pipnvp;
    3377         pipnvp = NULL;
    33783313    }
    33793314
     3315    if (playbackinfo)
     3316        delete playbackinfo;
     3317   
    33803318    activerbuffer  = prbuffer = pip.buffer;
    33813319    activerecorder = recorder = pip.recorder;
    33823320    tvchain                   = pip.chain;
     3321    playbackinfo              = pip.pginfo;
     3322    internalState             = GetPIPState(pipplayer);
    33833323
    3384     piprbuffer  = main.buffer;
    3385     piprecorder = main.recorder;
    3386     piptvchain  = main.chain;
    3387 
     3324    pipplayer->SetRingBuffer(main.buffer);
     3325    pipplayer->SetRecorder(main.recorder);
     3326    pipplayer->SetLiveTVChain(main.chain);
     3327    pipplayer->SetProgramInfo(main.pginfo);
     3328   
     3329    VERBOSE(VB_PLAYBACK, QString("TV SwapPIP: New InternalState is %1")
     3330            .arg(StateToString(internalState)));
     3331   
    33883332    prbuffer->Seek(0, SEEK_SET);
    33893333    prbuffer->Unpause();
    3390     StartPlayer(false);
    3391     activenvp = nvp;
    3392     nvp->FastForward(pip.frame/recorder->GetFrameRate());
    33933334
    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())
     3335    if (internalState == kState_WatchingRecording)
     3336        StartPlayer(true);
     3337    else
     3338        StartPlayer(false);
     3339
     3340    activenvp = nvp;
     3341    usleep(10000);
     3342    if (tvchain)
     3343        nvp->FastForward(pip.frame/recorder->GetFrameRate());
     3344   
     3345    pipplayer->GetRingBuffer()->Seek(0, SEEK_SET);
     3346    pipplayer->GetRingBuffer()->Unpause();
     3347 
     3348    if (use_nullvideo)
    34003349    {
    3401         piptvchain->ReloadAll();
    3402         usleep(5000);
     3350        pipplayer->StartPlaying(main.pginfo, pipislivetv, true);
     3351        if (pipplayer->IsPlaying())
     3352            activenvp->SetPIPPlayer(pipplayer->GetNVP());
    34033353    }
    3404     VERBOSE(VB_PLAYBACK, "PiP NVP Started -- restart");
    3405     pipnvp->FastForward(pip.frame/piprecorder->GetFrameRate());
    3406 
    3407     if (pipnvp->IsDecoderThreadAlive())
    3408         nvp->SetPipPlayer(pipnvp);
    34093354    else
     3355        pipplayer->StartPlaying(main.pginfo, pipislivetv);
     3356
     3357    if (pipplayer->IsPlaying())
    34103358    {
    3411         VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start");
    3412         TeardownPipPlayer();
     3359        if (!use_nullvideo)
     3360            pipplayer->Show();
     3361        if (pipplayer->GetLiveTVChain())
     3362        {
     3363            pipplayer->GetLiveTVChain()->ReloadAll();
     3364            usleep(5000);
     3365        }
    34133366    }
    34143367
    3415     ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
    3416     if (pginfo)
     3368    if (internalState == kState_WatchingLiveTV)
     3369        SetPseudoLiveTV(0, NULL, kPseudoNormalLiveTV);
     3370
     3371    if (pipplayer->IsLiveTV())
     3372        SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
     3373
     3374    if (pipplayer->GetLiveTVChain())
     3375        pipplayer->GetNVP()->FastForward(main.frame/pipplayer->GetRecorder()->GetFrameRate());
     3376
     3377    if (tvchain)
    34173378    {
    3418         SetCurrentlyPlaying(pginfo);
    3419         delete pginfo;
     3379        ProgramInfo *pginfo = tvchain->GetProgramAt(-1);
     3380        if (pginfo)
     3381        {
     3382            SetCurrentlyPlaying(pginfo);
     3383            delete pginfo;
     3384        }
    34203385    }
     3386    pipplayer->SetReinit(true);
    34213387}
    34223388
     3389TVState TV::GetPIPState(PIPPlayer *player)
     3390{
     3391    if (player->IsLiveTV())
     3392        return kState_WatchingLiveTV;
     3393    else if (RemoteGetRecordingStatus(player->GetProgramInfo(),0,0))
     3394        return kState_WatchingRecording;
     3395    else
     3396        return kState_WatchingPreRecorded;
     3397}
     3398
    34233399void TV::DoPlay(void)
    34243400{
    34253401    float time = 0.0;
     
    34743450    float time = 0.0;
    34753451
    34763452    if (paused)
     3453    {
    34773454        activenvp->Play(normal_speed, true);
     3455        if (pipplayer && pipplayer->IsPlaying())
     3456        {
     3457            pipplayer->GetNVP()->Play(normal_speed, true);
     3458            pipplayer->SetFrameRate(24.0); // need to increase fps after pause.
     3459            pipVideoTimer->start(2000);
     3460        }
     3461    }
    34783462    else
    34793463    {
    34803464        if (doing_ff_rew)
     
    34853469        }
    34863470       
    34873471        activenvp->Pause();
     3472        if (pipplayer && pipplayer->IsPlaying())
     3473        {
     3474            pipVideoTimer->stop();
     3475            pipplayer->GetNVP()->Pause();
     3476        }
    34883477    }
    34893478
    34903479    paused = !paused;
     
    38493838
    38503839    RemoteEncoder *testrec = NULL;
    38513840
    3852     if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
     3841    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer)
    38533842        return;
    38543843
    38553844    if (/*chanid || */!channum.isEmpty())
     
    53695358                menurunning = false;
    53705359                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    53715360            }
    5372             else if (piprecorder &&
    5373                      cardnum == piprecorder->GetRecorderNumber())
     5361            else if (pipplayer && pipplayer->GetRecorder() &&
     5362                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53745363            {
    53755364                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
    53765365                TogglePIPView();
     
    53885377                wantsToQuit = false;
    53895378                exitPlayer = true;
    53905379            }
    5391             else if (piprecorder &&
    5392                      cardnum == piprecorder->GetRecorderNumber())
     5380            else if (pipplayer && pipplayer->GetRecorder() &&
     5381                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53935382            {
    53945383                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
    53955384                TogglePIPView();
     
    54055394            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
    54065395
    54075396            if ((recorder    && cardnum == recorder->GetRecorderNumber()) ||
    5408                 (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     5397                (pipplayer && pipplayer->GetRecorder() &&
     5398                 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()))
    54095399            {
    54105400                if (watch)
    54115401                {
     
    54145404                    if (pi.FromStringList(list, 0))
    54155405                        SetPseudoLiveTV(s, &pi, kPseudoChangeChannel);
    54165406
    5417                     if (!s && pipnvp)
     5407                    if (!s && pipplayer)
    54185408                        TogglePIPView();
    54195409                }
    54205410                else
     
    64366426
    64376427    if (StateIsLiveTV(GetState()))
    64386428    {
    6439         bool freeRecorders = (pipnvp != NULL);
     6429        bool freeRecorders = (pipplayer != NULL);
    64406430        if (!freeRecorders)
    64416431            freeRecorders = RemoteGetFreeRecorderCount();
    64426432
     
    70767066{
    70777067    VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()");
    70787068
     7069    LiveTVChain *piptvchain = NULL;
     7070    if (pipplayer)
     7071        piptvchain = pipplayer->GetLiveTVChain();
     7072
    70797073    LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    70807074
    70817075    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//    VERBOSE(VB_IMPORTANT, QString("DELETE ME tmpw %1 tmph %2 letteradj %3 dispPixelAdj %4")
     1115//            .arg(tmpw).arg(tmph).arg(letterAdj).arg(dispPixelAdj));
     1116    switch (location)
     1117    {
     1118        default:
     1119        case kPIPTopLeft:
     1120            xpos = 30 + letterXadj;
     1121            ypos += 40 + letterYadj;
     1122            break;
     1123        case kPIPBottomLeft:
     1124            xpos = 30 + letterXadj;
     1125            ypos += frame_height - tmph - 40 - letterYadj;
     1126            break;
     1127        case kPIPTopRight:
     1128            xpos = frame_width  - tmpw - 30 - letterXadj;
     1129            ypos += 40 + letterXadj;
     1130            break;
     1131        case kPIPBottomRight:
     1132            xpos = frame_width  - tmpw - 30 - letterXadj;
     1133            ypos += frame_height - tmph - 40 - letterYadj;
     1134            break;
     1135    }
     1136    return QRect(xpos, ypos, tmpw, tmph);
     1137}
     1138
    10481139/**
    10491140 * \fn VideoOutput::DoPipResize(int,int)
    10501141 * \brief Sets up Picture in Picture image resampler.
     
    11111202    int pipw, piph;
    11121203
    11131204    VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
     1205
    11141206    float pipVideoAspect = pipplayer->GetVideoAspect();
    1115     uint  pipVideoWidth  = pipplayer->GetVideoWidth();
    1116     uint  pipVideoHeight = pipplayer->GetVideoHeight();
    11171207
    11181208    // If PiP is not initialized to values we like, silently ignore the frame.
    11191209    if ((video_aspect <= 0) || (pipVideoAspect <= 0) ||
     
    11231213        pipplayer->ReleaseCurrentFrame(pipimage);
    11241214        return;
    11251215    }
     1216   
     1217    QRect piprect = GetPIPRect(db_pip_location, pipplayer);
    11261218
    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 
     1219    pip_desired_display_size.setWidth((piprect.width() >> 1 ) << 1);
     1220    pip_desired_display_size.setHeight((piprect.height() >> 1) << 1);
     1221   
     1222   
    11601223    // Scale the image if we have to...
    11611224    unsigned char *pipbuf = pipimage->buf;
    11621225    if (pipw != pip_desired_display_size.width() ||
     
    11861249
    11871250
    11881251    // 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     }
     1252    int xoff = piprect.x();
     1253    int yoff = piprect.y();
    12111254
    12121255    // Copy Y (intensity values)
    12131256    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);
     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
     290void PIPPlayer::SetFrameRate(double fps)
     291{
     292    if (!pipnvp || pipnvp->GetFrameRate() == fps)
     293        return;
     294
     295    pipnvp->SetVideoParams(pipnvp->GetVideoWidth(),
     296                            pipnvp->GetVideoHeight(),
     297                            fps, 15);
     298}
     299
     300bool PIPPlayer::IsSameProgram(ProgramInfo *rec)
     301{
     302    if (!rec || !piprecinfo)
     303        return false;
     304
     305    if (piprecinfo->IsSameProgram(*rec))
     306        return true;
     307   
     308    return false;
     309}
     310
     311bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait)
     312{
     313    maxWait = (maxWait <= 0) ? 40000 : maxWait;
     314    MythTimer t;
     315    t.start();
     316    while (rec && !rec->IsRecording() && t.elapsed() < maxWait)
     317        usleep(5000);
     318    if (rec && !rec->IsRecording())
     319    {
     320        VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out");
     321        return false;
     322    }
     323    return true;
     324}
     325
     326void PIPPlayer::Hide(void)
     327{
     328    if (pipWindow && pipWindow->isVisible())
     329        pipWindow->hide();
     330}
     331
     332void PIPPlayer::Show(void)
     333{   
     334    if (pipWindow && pipWindow->isHidden())
     335        pipWindow->show();
     336}
     337
     338bool PIPPlayer::IsHidden(void)
     339{
     340    if (pipWindow && pipWindow->isHidden())
     341        return true;
     342    return false;
     343}
     344
     345void PIPPlayer::DisplaySoftwareScaledImage(void)
     346{
     347    if (!using_nullvideo)
     348        return;
     349   
     350    QPainter p(pipWindow);
     351    QSize size = pipWindow->size();
     352    float saspect = ((float)size.width())/ ((float)size.height());
     353    float vaspect = pipnvp->GetVideoAspect();
     354    size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
     355    size.setHeight(((size.height() + 7) / 8) * 8);
     356    size.setWidth( ((size.width()  + 7) / 8) * 8);
     357    const QImage &img = pipnvp->GetARGBFrame(size);
     358    p.drawImage(0, 0, img);
     359}
  • 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    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)
     
    546533        drawUsageBounds = area;
    547534    if (name.lower() == "cur_group")
    548535        drawCurGroupBounds = area;       
    549     
     536   
    550537}
    551538
    552539void PlaybackBox::parsePopup(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        int framerate;
     3486
     3487        if (expectingPopup ||
     3488            !(this == gContext->GetMainWindow()->currentWidget()))
     3489        {
     3490            return;
     3491        }
     3492        else if (previewPlayer->GetNVP() == NULL)
     3493            startPlayer(curitem);
     3494        else if (!previewPlayer->IsPlaying())
     3495            stopPlayer();
     3496        else
     3497        {
     3498            framerate = 10;
     3499            previewPlayer->SetFrameRate((float)framerate);
     3500        }
     3501    }       
    36983502}
    36993503
    37003504void PlaybackBox::processNetworkControlCommands(void)
     
    42864090        return;
    42874091    }
    42884092
    4289     killPlayerSafe();
    4290 
    42914093    iconhelp->addLayout(grid);
    42924094
    42934095    QButton *button = iconhelp->addButton(tr("Ok"));
     
    42974099
    42984100    delete iconhelp;
    42994101
    4300     previewVideoState = kChanging;
    43014102
    43024103    paintSkipUpdate = false;
    43034104    paintSkipCount = 2;
     
    43174118    QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false);
    43184119    label->setAlignment(Qt::AlignCenter);
    43194120
    4320     killPlayerSafe();
     4121    stopPlayer();
    43214122
    43224123}
    43234124
     
    43424143    paintSkipUpdate = false;
    43434144    paintSkipCount = 2;
    43444145
    4345     previewVideoState = kChanging;
    4346 
    43474146    setActiveWindow();
    43484147
    43494148    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;