Ticket #843: pipplayer.3.diff

File pipplayer.3.diff, 76.2 KB (added by skamithi, 13 years ago)

pipplayer.2.diff created using the latest mythtv-vid update.

  • 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;
     
    670673    NuppelVideoPlayer *pipplayer;
    671674    NuppelVideoPlayer *setpipplayer;
    672675    bool needsetpipplayer;
     676    bool ispip;
     677    bool softwareScalingPIP;
    673678
    674679    // Preview window support
    675680    unsigned char      *argb_buf;
  • libs/libmythtv/tv_play.cpp

     
    3939#include "DVDRingBuffer.h"
    4040#include "datadirect.h"
    4141#include "sourceutil.h"
     42#include "pipplayer.h"
    4243
    4344#ifndef HAVE_ROUND
    4445#define round(x) ((int) ((x) + 0.5))
     
    462463      lastProgram(NULL), jumpToProgram(false),
    463464      inPlaylist(false), underNetworkControl(false),
    464465      // Video Players
    465       nvp(NULL), pipnvp(NULL), activenvp(NULL),
     466      nvp(NULL), pipplayer(NULL), activenvp(NULL),
     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            pipVideoTimer->start(2000);
     3459        }
     3460    }
    34783461    else
    34793462    {
    34803463        if (doing_ff_rew)
     
    34853468        }
    34863469       
    34873470        activenvp->Pause();
     3471        if (pipplayer && pipplayer->IsPlaying())
     3472        {
     3473            pipVideoTimer->stop();
     3474            pipplayer->GetNVP()->Pause();
     3475        }
    34883476    }
    34893477
    34903478    paused = !paused;
     
    38493837
    38503838    RemoteEncoder *testrec = NULL;
    38513839
    3852     if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
     3840    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipplayer)
    38533841        return;
    38543842
    38553843    if (/*chanid || */!channum.isEmpty())
     
    53695357                menurunning = false;
    53705358                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    53715359            }
    5372             else if (piprecorder &&
    5373                      cardnum == piprecorder->GetRecorderNumber())
     5360            else if (pipplayer && pipplayer->GetRecorder() &&
     5361                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53745362            {
    53755363                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
    53765364                TogglePIPView();
     
    53885376                wantsToQuit = false;
    53895377                exitPlayer = true;
    53905378            }
    5391             else if (piprecorder &&
    5392                      cardnum == piprecorder->GetRecorderNumber())
     5379            else if (pipplayer && pipplayer->GetRecorder() &&
     5380                     cardnum == pipplayer->GetRecorder()->GetRecorderNumber())
    53935381            {
    53945382                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
    53955383                TogglePIPView();
     
    54055393            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
    54065394
    54075395            if ((recorder    && cardnum == recorder->GetRecorderNumber()) ||
    5408                 (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     5396                (pipplayer && pipplayer->GetRecorder() &&
     5397                 cardnum == pipplayer->GetRecorder()->GetRecorderNumber()))
    54095398            {
    54105399                if (watch)
    54115400                {
     
    54145403                    if (pi.FromStringList(list, 0))
    54155404                        SetPseudoLiveTV(s, &pi, kPseudoChangeChannel);
    54165405
    5417                     if (!s && pipnvp)
     5406                    if (!s && pipplayer)
    54185407                        TogglePIPView();
    54195408                }
    54205409                else
     
    64366425
    64376426    if (StateIsLiveTV(GetState()))
    64386427    {
    6439         bool freeRecorders = (pipnvp != NULL);
     6428        bool freeRecorders = (pipplayer != NULL);
    64406429        if (!freeRecorders)
    64416430            freeRecorders = RemoteGetFreeRecorderCount();
    64426431
     
    70767065{
    70777066    VERBOSE(VB_PLAYBACK, LOC + "UnpauseLiveTV()");
    70787067
     7068    LiveTVChain *piptvchain = NULL;
     7069    if (pipplayer)
     7070        piptvchain = pipplayer->GetLiveTVChain();
     7071
    70797072    LiveTVChain *chain = (activenvp == nvp) ? tvchain : piptvchain;
    70807073
    70817074    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 + QString("PIP is for %1").arg((islivetv) ? "live tv":"a recording"));
     109
     110    if (islivetv)
     111    {
     112        if (!(piprecorder && piprbuffer && piptvchain))
     113        {
     114            testrec = RemoteRequestRecorder();
     115
     116            if (!testrec || !testrec->IsValidRecorder())
     117            {
     118                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP failed to locate recorder");
     119                if (testrec)
     120                    delete testrec;
     121                return false;
     122            }
     123
     124            testrec->Setup();
     125
     126            piptvchain = new LiveTVChain();
     127            piptvchain->InitializeNewChain("PIP"+gContext->GetHostName());
     128            testrec->SpawnLiveTV(piptvchain->GetID(), true);
     129            piptvchain->ReloadAll();
     130            piprecinfo = piptvchain->GetProgramAt(-1);
     131            if (!piprecinfo)
     132            {
     133                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP cannot find live tv programinfo. Exiting");
     134                delete testrec;
     135                piptvchain->DestroyChain();
     136                delete piptvchain;
     137                return false;
     138            }
     139            else
     140            {
     141                QString playbackURL = piprecinfo->GetPlaybackURL();
     142                piptvchain->SetProgram(piprecinfo);
     143                piprbuffer = new RingBuffer(playbackURL, false);
     144                piprbuffer->SetLiveMode(piptvchain);
     145            }
     146
     147            piprecorder = testrec;
     148       
     149            if (!StartRecorder(piprecorder, -1))
     150            {
     151                VERBOSE(VB_IMPORTANT, LOC_ERR + "PIP recorder failed to start");
     152                return false;
     153            }
     154        }
     155    }
     156    else // pip is not Live TV
     157    {
     158        if (!piprecinfo)
     159            piprecinfo = new ProgramInfo(*rec);
     160        if (!piprbuffer)
     161            piprbuffer = new RingBuffer(piprecinfo->pathname, false, false, 1);
     162        if (!piprbuffer->IsOpen())
     163        {
     164            VERBOSE(VB_IMPORTANT, LOC_ERR +
     165                QString("Failed to open Ringbuffer %1")
     166                .arg(piprecinfo->pathname));
     167            return false;
     168        }
     169    }
     170
     171    // when starting pipplayer for the first time, always start
     172    // from the beginning
     173    if (reinit && piprecinfo)
     174        piprecinfo->setIgnoreBookmark(true);
     175       
     176    pipnvp = new NuppelVideoPlayer("pip player", piprecinfo);
     177    pipnvp->SetParentWidget(pipWindow);
     178    pipnvp->SetRingBuffer(piprbuffer);
     179    if (islivetv)
     180    {
     181        pipnvp->SetRecorder(piprecorder);
     182        pipnvp->SetLiveTVChain(piptvchain);
     183    }
     184    else
     185        pipnvp->SetLength(piprecinfo->CalculateLength());
     186       
     187
     188    // setAsPIP is true if null video output is used
     189    // PIP will be embedded in XV
     190    if (using_nullvideo)
     191    {
     192        pipnvp->SetAsPIP(true);
     193    }
     194    else
     195        pipnvp->SetAsPIP(false);
     196
     197    VERBOSE(VB_PLAYBACK, "PIP Waiting for NVP");
     198    pthread_create(&pipdecode, NULL, SpawnPIPVideoThread, pipnvp);
     199    while (!pipnvp->IsPlaying() && pipnvp->IsDecoderThreadAlive())
     200    {
     201        usleep(5000);
     202    }
     203
     204    VERBOSE(VB_PLAYBACK, " PIP NVP Started");
     205    return true;
     206}
     207
     208void PIPPlayer::StopPlaying(void)
     209{
     210   
     211    if (!pipnvp)
     212        return;
     213
     214    if (pipnvp->IsPlaying())
     215    {
     216        if (reinit)
     217            piprbuffer->StopReads();
     218        piprbuffer->Pause();
     219        piprbuffer->WaitForPause();
     220        pipnvp->StopPlaying();
     221    }
     222   
     223    VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): Stopped Playing");
     224    {
     225        pthread_join(pipdecode, NULL);
     226        delete pipnvp;
     227        pipnvp = NULL;
     228    }
     229
     230    if (reinit)
     231    {
     232        if (islivetv && piprecorder )
     233            piprecorder->StopLiveTV();
     234   
     235        Reinitialize();
     236    }
     237   
     238    VERBOSE(VB_PLAYBACK, LOC + "KillPlayer(): NVP deleted");
     239}
     240
     241/*
     242 * \brief set pip ringbuffer if pip is not playing
     243 */
     244void PIPPlayer::SetRingBuffer(RingBuffer *rbuffer)
     245{
     246    if (!IsPlaying())
     247        piprbuffer = rbuffer;
     248}
     249
     250/*
     251 * \brief set pip tvchain if pip is not playing
     252 */
     253void PIPPlayer::SetLiveTVChain(LiveTVChain *tvchain)
     254{
     255    if (!IsPlaying())
     256        piptvchain = tvchain;
     257}
     258
     259/*
     260 * \brief set pip recorder if pip is not playing
     261 */
     262void PIPPlayer::SetRecorder(RemoteEncoder  *recorder)
     263{
     264    if (!IsPlaying())
     265        piprecorder = recorder;
     266}
     267
     268void PIPPlayer::SetProgramInfo(ProgramInfo *pginfo)
     269{
     270    if (!IsPlaying())
     271    {
     272        if (piprecinfo)
     273            delete piprecinfo;
     274        piprecinfo = pginfo;
     275    }
     276}
     277
     278void PIPPlayer::SetFrameRate(double fps)
     279{
     280    if (!pipnvp || pipnvp->GetFrameRate() == fps)
     281        return;
     282
     283    pipnvp->SetVideoParams(pipnvp->GetVideoWidth(),
     284                            pipnvp->GetVideoHeight(),
     285                            fps, 15);
     286}
     287
     288bool PIPPlayer::IsSameProgram(ProgramInfo *rec)
     289{
     290    if (!rec || !piprecinfo)
     291        return false;
     292
     293    if (piprecinfo->IsSameProgram(*rec))
     294        return true;
     295   
     296    return false;
     297}
     298
     299bool PIPPlayer::StartRecorder(RemoteEncoder *rec, int maxWait)
     300{
     301    maxWait = (maxWait <= 0) ? 40000 : maxWait;
     302    MythTimer t;
     303    t.start();
     304    while (rec && !rec->IsRecording() && t.elapsed() < maxWait)
     305        usleep(5000);
     306    if (rec && !rec->IsRecording())
     307    {
     308        VERBOSE(VB_IMPORTANT, LOC_ERR + "recorder startup failed. Timed out");
     309        return false;
     310    }
     311    return true;
     312}
     313
     314void PIPPlayer::Hide(void)
     315{
     316    if (pipWindow && pipWindow->isVisible())
     317        pipWindow->hide();
     318}
     319
     320void PIPPlayer::Show(void)
     321{   
     322    if (pipWindow && pipWindow->isHidden())
     323        pipWindow->show();
     324}
     325
     326bool PIPPlayer::IsHidden(void)
     327{
     328    if (pipWindow && pipWindow->isHidden())
     329        return true;
     330    return false;
     331}
     332
     333void PIPPlayer::DisplaySoftwareScaledImage(void)
     334{
     335    if (!using_nullvideo)
     336        return;
     337   
     338    QPainter p(pipWindow);
     339    QSize size = pipWindow->size();
     340    float saspect = ((float)size.width())/ ((float)size.height());
     341    float vaspect = pipnvp->GetVideoAspect();
     342    size.setHeight((int) ceil(size.height() * (saspect / vaspect)));
     343    size.setHeight(((size.height() + 7) / 8) * 8);
     344    size.setWidth( ((size.width()  + 7) / 8) * 8);
     345    const QImage &img = pipnvp->GetARGBFrame(size);
     346    p.drawImage(0, 0, img);
     347}
  • 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      previewPlayer(NULL), previewVideoStartTimer(new QTimer(this)),
    266267      previewVideoRefreshTimer(new QTimer(this)),
    267       previewVideoBrokenRecId(0),       previewVideoState(kStopped),
    268       previewVideoStartTimerOn(false),  previewVideoEnabled(false),
    269       previewVideoPlaying(false),       previewVideoThreadRunning(false),
    270       previewVideoKillState(kDone),
     268      previewTimeout(2000), software_scaled(false),
    271269      // Preview Image Variables
    272270      previewPixmapEnabled(false),      previewPixmap(NULL),
    273271      previewSuspend(false),            previewChanid(""),
     
    369367    connected = FillList();
    370368
    371369    // connect up timers...
    372     connect(previewVideoRefreshTimer, SIGNAL(timeout()),
     370    connect(previewVideoStartTimer,        SIGNAL(timeout()),
    373371            this,                     SLOT(timeout()));
     372    connect(previewVideoRefreshTimer,       SIGNAL(timeout()),
     373            this,                     SLOT(refreshVideo()));
    374374    connect(freeSpaceTimer,           SIGNAL(timeout()),
    375375            this,                     SLOT(setUpdateFreeSpace()));
    376376    connect(fillListTimer,            SIGNAL(timeout()),
    377377            this,                     SLOT(listChanged()));
    378378
    379379    // preview video & preview pixmap init
    380     previewVideoRefreshTimer->start(500);
    381380    previewStartts = QDateTime::currentDateTime();
    382 
     381    previewVideoStartTimer->start(previewTimeout);
     382    previewVideoRefreshTimer->start(50);
    383383    // misc setup
    384384    updateBackground();
    385385    setNoErase();
     
    398398    gContext->removeListener(this);
    399399    gContext->removeCurrentLocation();
    400400
    401     if (!m_player)
    402         killPlayerSafe();
     401    killPlayer();
     402   
     403    if (previewVideoStartTimer)
     404    {
     405        previewVideoStartTimer->disconnect(this);
     406        previewVideoStartTimer->deleteLater();
     407        previewVideoStartTimer = NULL;
     408    }
    403409
    404410    if (previewVideoRefreshTimer)
    405411    {
     
    464470        delete previewPixmap;
    465471        previewPixmap = NULL;
    466472    }
    467 }
    468473
    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;
    496474}
    497475
    498476void PlaybackBox::LoadWindow(QDomElement &element)
     
    523501            }
    524502        }
    525503    }
     504
     505    if (previewVideoEnabled)
     506    {
     507        previewPlayer = PIPPlayer::Create(drawVideoBounds);
     508        if (previewPlayer)
     509            previewPlayer->Hide();
     510        previewPixmapEnabled = true;
     511    }
    526512}
    527513
    528514void PlaybackBox::parseContainer(QDomElement &element)
     
    596582
    597583void PlaybackBox::exitWin()
    598584{
     585    killPlayer();
    599586    if (m_player)
    600587    {
    601588        if (curitem)
     
    603590        curitem = NULL;
    604591        pbbIsVisibleCond.wakeAll();
    605592    }
    606     else
    607         killPlayerSafe();
    608 
    609593    accept();
    610594}
    611595
     
    785769    QMap<QString, QString> infoMap;
    786770    QPainter tmp(&pix);
    787771       
    788     if (previewVideoPlaying)
    789         previewVideoState = kChanging;
    790772
    791773    LayerSet *container = NULL;
    792774    if (type != Delete)
     
    799781        if (curitem)
    800782            curitem->ToMap(infoMap);
    801783       
    802         if ((previewVideoEnabled == 0) &&
    803             (previewPixmapEnabled == 0))
     784        if (previewPixmapEnabled == 0)
    804785            container->UseAlternateArea(true);
    805786
    806787        container->ClearAllText();
     
    845826    tmp.end();
    846827    p->drawPixmap(pr.topLeft(), pix);
    847828
    848     previewVideoStartTimer.start();
    849     previewVideoStartTimerOn = true;
    850829}
    851830
    852831void PlaybackBox::updateInfo(QPainter *p)
     
    883862    // If we're displaying group info don't update the video.
    884863    if (inTitle && haveGroupInfoSet)
    885864        return;
    886 
     865   
    887866    /* show a still frame if the user doesn't want a video preview or nvp
    888867     * hasn't started playing the video preview yet */
    889     if (curitem && !playingSomething &&
    890         (!previewVideoEnabled             ||
    891          !previewVideoPlaying             ||
    892          (previewVideoState == kStarting) ||
    893          (previewVideoState == kChanging)))
     868    if ((curitem && previewPixmapEnabled && !previewPlayer) ||
     869         (curitem && previewPlayer && previewPlayer->IsHidden()))
    894870    {
    895871        QPixmap temp = getPixmap(curitem);
    896872        if (temp.width() > 0)
    897873            p->drawPixmap(drawVideoBounds.x(), drawVideoBounds.y(), temp);
    898874    }
    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))
     875   
     876    if (curitem && previewVideoEnabled && previewPlayer &&
     877            !previewPlayer->IsHidden())
    909878    {
    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         }
     879        if (!previewPlayer->IsSameProgram(curitem))
     880            stopPlayer();
    964881        else
    965         {
    966             // already dead, so clean up
    967             killPlayer();
    968             return;
    969         }
     882            previewPlayer->GetNVP()->ExposeEvent();
    970883    }
    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     }
     884   
     885    previewVideoStartTimer->changeInterval(previewTimeout);
    1010886}
    1011887
    1012888void PlaybackBox::updateUsage(QPainter *p)
     
    13601236    if (!inTitle)
    13611237    {
    13621238        if (haveGroupInfoSet)
    1363             killPlayerSafe();
     1239            killPlayer();
    13641240       
    13651241        inTitle = true;
    13661242        paintSkipUpdate = false;
     
    19641840    return (progCache != NULL);
    19651841}
    19661842
    1967 static void *SpawnPreviewVideoThread(void *param)
     1843void PlaybackBox::killPlayer(void)
    19681844{
    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)
     1845    if (previewPlayer)
    19821846    {
    1983         previewVideoKillState = kDone;
    1984         return true;
     1847        stopPlayer();
     1848        delete previewPlayer;
     1849        previewPlayer = NULL;
    19851850    }
    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;
    20261851}       
    20271852
    20281853void PlaybackBox::startPlayer(ProgramInfo *rec)
    20291854{
    2030     previewVideoPlaying = true;
    2031 
    2032     if (rec != NULL)
     1855    ignoreKeyPressEvents = true;
     1856    QMutexLocker locker(&previewVideoLock);
     1857    if (rec != NULL && previewPlayer)
    20331858    {
    2034         // Don't keep trying to open broken files when just sitting on entry
    2035         if (previewVideoBrokenRecId &&
    2036             previewVideoBrokenRecId == rec->recordid)
     1859        previewPlayer->Show();
     1860        if (!software_scaled)
     1861            previewPlayer->StartPlaying(rec, false);
     1862        if (!previewPlayer->IsPlaying())
    20371863        {
    2038             return;
     1864            software_scaled = true;
     1865            previewPlayer->StartPlaying(rec, false, true);
    20391866        }
     1867    }
     1868    ignoreKeyPressEvents = false;
     1869}
    20401870
    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);
     1871void PlaybackBox::stopPlayer(void)
     1872{
     1873    ignoreKeyPressEvents = true;
     1874    QMutexLocker locker(&previewVideoLock);
     1875    if (previewPlayer)
     1876    {
     1877        previewPlayer->StopPlaying();
     1878        previewPlayer->Hide();
    20821879    }
     1880    ignoreKeyPressEvents = false;
    20831881}
    20841882
    20851883void PlaybackBox::playSelectedPlaylist(bool random)
    20861884{
    2087     previewVideoState = kStopping;
    20881885
    20891886    if (!curitem)
    20901887        return;
     
    21151912
    21161913void PlaybackBox::playSelected()
    21171914{
    2118     previewVideoState = kStopping;
    21191915
    21201916    if (!curitem)
    21211917        return;
     
    21371933
    21381934void PlaybackBox::stopSelected()
    21391935{
    2140     previewVideoState = kStopping;
    21411936
    21421937    if (!curitem)
    21431938        return;
     
    21471942
    21481943void PlaybackBox::deleteSelected()
    21491944{
    2150     previewVideoState = kStopping;
    21511945
    21521946    if (!curitem)
    21531947        return;
     
    21611955
    21621956void PlaybackBox::upcoming()
    21631957{
    2164     previewVideoState = kStopping;
    21651958
    21661959    if (!curitem)
    21671960        return;
     
    21801973
    21811974void PlaybackBox::customEdit()
    21821975{
    2183     previewVideoState = kStopping;
    21841976
    21851977    if (!curitem)
    21861978        return;
     
    22031995
    22041996void PlaybackBox::details()
    22051997{
    2206     previewVideoState = kStopping;
    22071998
    22081999    if (!curitem)
    22092000        return;
     
    22162007
    22172008void PlaybackBox::selected()
    22182009{
    2219     previewVideoState = kStopping;
    22202010
    22212011    if (inTitle && haveGroupInfoSet)
    22222012    {
     
    22362026
    22372027void PlaybackBox::showMenu()
    22382028{
    2239     killPlayerSafe();
     2029    stopPlayer();
    22402030
    22412031    popup = new MythPopupBox(gContext->GetMainWindow(), drawPopupSolid,
    22422032                             drawPopupFgColor, drawPopupBgColor,
     
    22992089
    23002090bool PlaybackBox::play(ProgramInfo *rec, bool inPlaylist)
    23012091{
     2092    killPlayer();
     2093
    23022094    bool playCompleted = false;
    23032095
    23042096    if (!rec)
     
    23272119    ProgramInfo *tvrec = new ProgramInfo(*rec);
    23282120
    23292121    setEnabled(false);
    2330     previewVideoState = kKilling; // stop preview playback and don't restart it
    23312122    playingSomething = true;
    23322123
    23332124    playCompleted = TV::StartTV(tvrec, false, inPlaylist, underNetworkControl);
     
    23352126    playingSomething = false;
    23362127    setEnabled(true);
    23372128
    2338 
    2339     previewVideoState = kStarting; // restart playback preview
    2340 
    23412129    delete tvrec;
    23422130
    23432131    connected = FillList();
    23442132
     2133    if (previewVideoEnabled && !previewPlayer)
     2134    {
     2135        previewPlayer = PIPPlayer::Create(drawVideoBounds);
     2136        if (previewPlayer)
     2137            previewPlayer->Hide();
     2138    }
     2139
    23452140    return playCompleted;
    23462141}
    23472142
     
    23532148bool PlaybackBox::doRemove(ProgramInfo *rec, bool forgetHistory,
    23542149                           bool forceMetadataDelete)
    23552150{
    2356     previewVideoBrokenRecId = rec->recordid;
    2357     killPlayerSafe();
     2151    stopPlayer();
    23582152
    23592153    if (playList.grep(rec->MakeUniqueKey()).count())
    23602154        togglePlayListItem(rec);
     
    23672161
    23682162void PlaybackBox::remove(ProgramInfo *toDel)
    23692163{
    2370     previewVideoState = kStopping;
    23712164
    23722165    if (delitem)
    23732166        delete delitem;
     
    23782171
    23792172void PlaybackBox::showActions(ProgramInfo *toExp)
    23802173{
    2381     killPlayer();
     2174    stopPlayer();
    23822175
    23832176    if (delitem)
    23842177        delete delitem;
     
    30412834void PlaybackBox::initPopup(MythPopupBox *popup, ProgramInfo *program,
    30422835                            QString message, QString message2)
    30432836{
    3044     killPlayerSafe();
     2837    stopPlayer();
    30452838
    30462839    QDateTime recstartts = program->recstartts;
    30472840    QDateTime recendts = program->recendts;
     
    31502943
    31512944    cancelPopup();
    31522945
    3153     previewVideoState = kChanging;
    31542946
    3155     previewVideoRefreshTimer->start(500);
    31562947}
    31572948
    31582949void PlaybackBox::doStop(void)
     
    31642955
    31652956    stop(delitem);
    31662957
    3167     previewVideoState = kChanging;
    31682958
    3169     previewVideoRefreshTimer->start(500);
    31702959}
    31712960
    31722961void PlaybackBox::showProgramDetails()
     
    33163105
    33173106    cancelPopup();
    33183107
    3319     previewVideoState = kChanging;
    33203108
    3321     previewVideoRefreshTimer->start(500);
    33223109}
    33233110
    33243111void PlaybackBox::doPlaylistDelete(void)
     
    33623149
    33633150    bool result = doRemove(delitem, false, false);
    33643151
    3365     previewVideoState = kChanging;
    33663152
    3367     previewVideoRefreshTimer->start(500);
    33683153
    33693154    if (result)
    33703155    {
     
    33973182
    33983183    doRemove(delitem, true, true);
    33993184
    3400     previewVideoState = kChanging;
    34013185
    3402     previewVideoRefreshTimer->start(500);
    34033186}
    34043187
    34053188void PlaybackBox::doDeleteForgetHistory(void)
     
    34223205
    34233206    bool result = doRemove(delitem, true, false);
    34243207
    3425     previewVideoState = kChanging;
    34263208
    3427     previewVideoRefreshTimer->start(500);
    34283209
    34293210    if (result)
    34303211    {
     
    34993280    delete delitem;
    35003281    delitem = NULL;
    35013282
    3502     previewVideoState = kChanging;
    3503 
    35043283    connected = FillList();     
    35053284    update(drawListBounds);
    35063285}
     
    35213300    delete delitem;
    35223301    delitem = NULL;
    35233302
    3524     previewVideoState = kChanging;
    35253303
    35263304    connected = FillList();     
    35273305    update(drawListBounds);
     
    35703348
    35713349    cancelPopup();
    35723350
    3573     previewVideoState = kChanging;
    35743351}
    35753352
    35763353void PlaybackBox::toggleView(ViewMask itemMask, bool setOn)
     
    35903367    if (!rec)
    35913368        return;
    35923369
    3593     previewVideoState = kStopping;
    3594 
    35953370    if (!rec)
    35963371        return;
    35973372
     
    36883463    update(drawListBounds);
    36893464}
    36903465
     3466void PlaybackBox::refreshVideo(void)
     3467{
     3468    if (previewPlayer &&
     3469        previewPlayer->IsPlaying() &&
     3470        previewPlayer->UsingNullVideo())
     3471    {
     3472        QMutexLocker locker(&previewVideoLock);
     3473        previewPlayer->DisplaySoftwareScaledImage();
     3474    }
     3475}
     3476
    36913477void PlaybackBox::timeout(void)
    36923478{
    36933479    if (titleList.count() <= 1)
    36943480        return;
    36953481
    3696     if (previewVideoEnabled)
    3697         update(drawVideoBounds);
     3482    if (previewPlayer)
     3483    {
     3484        int framerate;
     3485
     3486        if (expectingPopup ||
     3487            !(this == gContext->GetMainWindow()->currentWidget()))
     3488        {
     3489            return;
     3490        }
     3491        else if (previewPlayer->GetNVP() == NULL)
     3492            startPlayer(curitem);
     3493        else if (!previewPlayer->IsPlaying())
     3494            stopPlayer();
     3495        else
     3496        {
     3497            framerate = 10;
     3498            previewPlayer->SetFrameRate((float)framerate);
     3499        }
     3500    }       
    36983501}
    36993502
    37003503void PlaybackBox::processNetworkControlCommands(void)
     
    42864089        return;
    42874090    }
    42884091
    4289     killPlayerSafe();
    4290 
    42914092    iconhelp->addLayout(grid);
    42924093
    42934094    QButton *button = iconhelp->addButton(tr("Ok"));
     
    42974098
    42984099    delete iconhelp;
    42994100
    4300     previewVideoState = kChanging;
    43014101
    43024102    paintSkipUpdate = false;
    43034103    paintSkipCount = 2;
     
    43174117    QLabel *label = recGroupPopup->addLabel(title, MythPopupBox::Large, false);
    43184118    label->setAlignment(Qt::AlignCenter);
    43194119
    4320     killPlayerSafe();
     4120    stopPlayer();
    43214121
    43224122}
    43234123
     
    43424142    paintSkipUpdate = false;
    43434143    paintSkipCount = 2;
    43444144
    4345     previewVideoState = kChanging;
    4346 
    43474145    setActiveWindow();
    43484146
    43494147    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;