Ticket #2287: multi-pip-v1.patch

File multi-pip-v1.patch, 140.6 KB (added by danielk, 12 years ago)

Adds Multiple PiP window support.

  • libs/libmythtv/NuppelVideoPlayer.cpp

     
    214214      audio_channels(2),            audio_bits(-1),
    215215      audio_samplerate(44100),      audio_stretchfactor(1.0f),
    216216      audio_codec(NULL),
    217       // Picture-in-Picture
    218       pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false),
     217      // Picture-in-Picture stuff
     218      pip_active(false),
    219219      // Preview window support
    220220      argb_buf(NULL),               argb_size(0,0),
    221221      yuv2argb_conv(yuv2rgb_init_mmx(32, MODE_RGB)),
     
    24672467                    player_ctx->buffer->DVD()->InStillFrame() &&
    24682468                    videoOutput->ValidVideoFrames() < 3)
    24692469                {
    2470                     videoOutput->ProcessFrame(buffer, NULL, NULL, pipplayer);
     2470                    videoOutput->ProcessFrame(
     2471                        buffer, NULL, NULL, pip_players);
    24712472                }
    24722473                else
    24732474                {
    24742475                    videoOutput->ProcessFrame(
    2475                         buffer, osd, videoFilters, pipplayer);
     2476                        buffer, osd, videoFilters,
     2477                        pip_players);
    24762478                }
    24772479                videofiltersLock.unlock();
    24782480            }
     
    26322634    DisplayDVDButton();
    26332635
    26342636    videofiltersLock.lock();
    2635     videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
     2637    videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
    26362638    videofiltersLock.unlock();
    26372639
    26382640    videoOutput->PrepareFrame(NULL, kScan_Ignore);
     
    28572859        player_ctx->buffer->DVD()->InStillFrame() &&
    28582860        videoOutput->ValidVideoFrames() < 3)
    28592861    {
    2860         videoOutput->ProcessFrame(frame, NULL, NULL, pipplayer);
     2862        videoOutput->ProcessFrame(frame, NULL, NULL, pip_players);
    28612863    }
    28622864    else
    2863         videoOutput->ProcessFrame(frame, osd, videoFilters, pipplayer);
     2865    {
     2866        videoOutput->ProcessFrame(frame, osd, videoFilters, pip_players);
     2867    }
    28642868    videofiltersLock.unlock();
    28652869
    28662870    if (audioOutput && !audio_paused && audioOutput->IsPaused())
     
    29532957
    29542958    while (!killvideo)
    29552959    {
    2956         if (needsetpipplayer)
    2957         {
    2958             pipplayer = setpipplayer;
    2959             needsetpipplayer = false;
    2960             PIPState state = player_ctx->GetPIPState();
    2961             if (m_tv && (state == kPIPOff  || state == kPBPLeft))
    2962                 m_tv->WakeSetPIPPlayerCond();
    2963             if (videoOutput)
    2964                 videoOutput->PadPIPImage(false);
    2965         }
     2960        HandlePIPPlayerLists(4);
    29662961
    29672962        if (player_ctx->buffer->isDVD())
    29682963        {
     
    30453040
    30463041    while (!killvideo)
    30473042    {
    3048         if (needsetpipplayer)
    3049         {
    3050             pipplayer = setpipplayer;
    3051             needsetpipplayer = false;
    3052         }
     3043        HandlePIPPlayerLists(1);
    30533044
    30543045        resetvideo = false;
    30553046        SetVideoActuallyPaused(pausevideo);
     
    30573048        if (pausevideo)
    30583049        {
    30593050            videofiltersLock.lock();
    3060             videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
     3051            videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
    30613052            videofiltersLock.unlock();
    30623053        }
    30633054        else
     
    30673058                ShowText();
    30683059
    30693060            videofiltersLock.lock();
    3070             videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
     3061            videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
    30713062            videofiltersLock.unlock();
    30723063        }
    30733064
     
    32493240    }
    32503241    else
    32513242    {
     3243        if (player_ctx)
     3244            player_ctx->SetNVPChangingBuffers(true);
    32523245        GetDecoder()->SetReadAdjust(player_ctx->buffer->SetAdjustFilesize());
    32533246        GetDecoder()->SetWaitForChange();
    3254         if (m_tv && player_ctx && !player_ctx->isPIP())
    3255             m_tv->SetIgnoreKeys(true);
    32563247    }
    32573248
    32583249    delete pginfo;
     
    32923283
    32933284    player_ctx->buffer->Unpause();
    32943285
    3295     if (m_tv && player_ctx && !player_ctx->isPIP())
    3296         m_tv->SetIgnoreKeys(false);
     3286    player_ctx->SetNVPChangingBuffers(false);
    32973287
    32983288    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    32993289    player_ctx->tvchain->SetProgram(*player_ctx->playingInfo);
     
    38663856        GetDecoder()->setTranscoding(value);
    38673857};
    38683858
     3859bool NuppelVideoPlayer::AddPIPPlayer(
     3860    NuppelVideoPlayer *pip, PIPLocation loc, uint timeout)
     3861{
     3862    QMutexLocker locker(&pip_players_lock);
     3863    pip_players_add[pip] = loc;
     3864
     3865    pip_players_wait.wait(&pip_players_lock, timeout);
     3866
     3867    if (pip_players.find(pip) != pip_players.end())
     3868        return true;
     3869
     3870    PIPMap::iterator it = pip_players_add.find(pip);
     3871    if (it != pip_players_add.end())
     3872        pip_players_add.erase(it);
     3873
     3874    return false;
     3875}
     3876
     3877bool NuppelVideoPlayer::RemovePIPPlayer(NuppelVideoPlayer *pip, uint timeout)
     3878{
     3879    QMutexLocker locker(&pip_players_lock);
     3880
     3881    pip_players_rm[pip] = kPIP_END;
     3882
     3883    pip_players_wait.wait(&pip_players_lock, timeout);
     3884
     3885    if (pip_players.find(pip) == pip_players.end())
     3886        return true;
     3887
     3888    PIPMap::iterator it = pip_players_rm.find(pip);
     3889    if (it != pip_players_rm.end())
     3890        pip_players_rm.erase(it);
     3891
     3892    return false;
     3893}
     3894
     3895void NuppelVideoPlayer::HandlePIPPlayerLists(uint max_cnt)
     3896{
     3897    QMutexLocker locker(&pip_players_lock);
     3898    PIPMap::const_iterator it = pip_players_rm.begin();
     3899    for (; it != pip_players_rm.end(); ++it)
     3900    {
     3901        PIPMap::iterator it2 = pip_players.find(it.key());
     3902        if (it2 != pip_players.end())
     3903            pip_players.erase(it2);
     3904    }
     3905
     3906    for (it = pip_players_add.begin();
     3907         (it != pip_players_add.end()) &&
     3908         ((uint)pip_players.size() <= max_cnt); ++it)
     3909    {
     3910        if (pip_players.find(it.key())    == pip_players.end() &&
     3911            pip_players_rm.find(it.key()) == pip_players_rm.end())
     3912        {
     3913            pip_players[it.key()] = *it;
     3914        }
     3915    }
     3916    pip_players_add.clear();
     3917    pip_players_rm.clear();
     3918    pip_players_wait.wakeAll();
     3919}
     3920
     3921PIPLocation NuppelVideoPlayer::GetNextPIPLocation(void) const
     3922{
     3923    QMutexLocker locker(&pip_players_lock);
     3924    PIPMap sim_pip_players = pip_players;
     3925
     3926    PIPMap::const_iterator it = pip_players_rm.begin();
     3927    for (; it != pip_players_rm.end(); ++it)
     3928    {
     3929        PIPMap::iterator it2 = sim_pip_players.find(it.key());
     3930        if (it2 != sim_pip_players.end())
     3931            sim_pip_players.erase(it2);
     3932    }
     3933
     3934    for (it = pip_players_add.begin(); it != pip_players_add.end(); ++it)
     3935    {
     3936        if (sim_pip_players.find(it.key()) == sim_pip_players.end() &&
     3937            pip_players_rm.find(it.key())  == pip_players_rm.end())
     3938        {
     3939            sim_pip_players[it.key()] = *it;
     3940        }
     3941    }
     3942
     3943    // order of preference, could be stored in db if we want it configurable
     3944    PIPLocation ols[] =
     3945        { kPIPTopLeft, kPIPTopRight, kPIPBottomLeft, kPIPBottomRight };
     3946
     3947    for (uint i = 0; i < sizeof(ols)/sizeof(PIPLocation); i++)
     3948    {
     3949        PIPMap::const_iterator it = sim_pip_players.begin();
     3950        for (; it != sim_pip_players.end() && (*it != ols[i]); ++it);
     3951
     3952        if (it == sim_pip_players.end())
     3953            return ols[i];
     3954    }
     3955
     3956    return kPIP_END;
     3957}
     3958
    38693959void NuppelVideoPlayer::WrapTimecode(long long &timecode, TCTypes tc_type)
    38703960{
    38713961    if ((tc_type == TC_AUDIO) && (tc_wrap[TC_AUDIO] == LONG_LONG_MIN))
  • libs/libmythtv/videooutwindow.cpp

     
    5454VideoOutWindow::VideoOutWindow() :
    5555    // DB settings
    5656    db_move(0, 0), db_scale_horiz(0.0f), db_scale_vert(0.0f),
    57     db_pip_location(kPIPTopLeft), db_pip_size(26),
     57    db_pip_size(26),
    5858    db_scaling_allowed(true),
    5959
    6060    // Manual Zoom
     
    8282    embedding(false), needrepaint(false),
    8383    allowpreviewepg(true), pip_state(kPIPOff)
    8484{
    85     db_pip_location = (PIPLocation) gContext->GetNumSetting(
    86         "PIPLocation", (int) kPIPTopLeft);
    87 
    8885    db_pip_size = gContext->GetNumSetting("PIPSize", 26);
    8986
    9087    db_move = QPoint(gContext->GetNumSetting("xScanDisplacement", 0),
     
    732729 * \brief Determines PIP Window size and Position.
    733730 */
    734731QRect VideoOutWindow::GetPIPRect(
    735     int location, NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
     732    PIPLocation location, NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
    736733{
    737734    QRect position;
    738735
  • libs/libmythtv/osdlistbtntype.cpp

     
    682682    m_initialized = true;
    683683}
    684684
     685#include <cassert>
    685686void OSDListBtnType::InitItem(
    686687    OSDTypeImage &osdImg, uint width, uint height,
    687688    QColor beg, QColor end, int alpha)
     
    698699        *ptr = black;
    699700    for (uint y = 1; y < height - 1; y++)
    700701    {
     702        if ((((uchar*)ptr)-data) >= 4 * width * height)
     703            break;
     704
     705        assert((((uchar*)ptr)-data) < 4 * width * height);
     706        *ptr = black; ptr++;
     707
    701708        int r = (int) (beg.red()   + (y * rstep));
    702709        int g = (int) (beg.green() + (y * gstep));
    703710        int b = (int) (beg.blue()  + (y * bstep));
    704711        uint32_t color = qRgba(r,g,b,alpha);
    705         *ptr = black; ptr++;
    706         for (uint x = 1; x < width - 1; x++, ptr++)
     712        for (uint x = 1;
     713             (x < width - 1) && ((((uchar*)ptr)-data) < 4 * width * height);
     714             x++, ptr++)
     715        {
     716            assert((((uchar*)ptr)-data) < 4 * width * height);
    707717            *ptr = color;
     718        }
     719
     720        if ((((uchar*)ptr)-data) >= 4 * width * height)
     721            break;
     722
     723        assert((((uchar*)ptr)-data) < 4 * width * height);
    708724        *ptr = black; ptr++;
    709725    }
    710     for (uint x = 0; x < width; x++, ptr++)
    711         *ptr = black;
     726    if ((((uchar*)ptr)-data) < 4 * width * height)
     727    {
     728        for (uint x = 0; x < width; x++, ptr++)
     729        {
     730            assert((((uchar*)ptr)-data) < 4 * width * height);
     731            *ptr = black;
     732        }
     733    }
    712734
    713735    {
    714736        QImage img;
  • libs/libmythtv/avformatdecoder.cpp

     
    902902    if (!fmt)
    903903    {
    904904        VERBOSE(VB_IMPORTANT, LOC_ERR +
    905                 QString("Probe failed for file: \"%1\".").arg(filename));
     905                QString("Probe failed for file: '%1' probe size %2.")
     906                .arg(filename).arg(probe.buf_size));
    906907        return -1;
    907908    }
     909    VERBOSE(VB_PLAYBACK, LOC +
     910            QString("Probe suceeded for file: '%1' probe size %2.")
     911            .arg(filename).arg(probe.buf_size));
    908912
    909913    fmt->flags |= AVFMT_NOFILE;
    910914
  • libs/libmythtv/tv_play.h

     
    149149
    150150    // LiveTV commands
    151151    bool LiveTV(bool showDialogs = true, bool startInGuide = false);
    152     /// This command is used to exit the player in order to record using
    153     /// the recording being used by LiveTV.
    154     void StopLiveTV(void) { SetExitPlayer(true, true); }
    155152
    156153    // Embedding commands for the guidegrid to use in LiveTV
    157154    void EmbedOutput(PlayerContext*, WId wid, int x, int y, int w, int h);
     
    183180    bool IsBookmarkAllowed(const PlayerContext*) const;
    184181    bool IsDeleteAllowed(const PlayerContext*) const;
    185182
    186     bool CreatePBP(PlayerContext*, const ProgramInfo *info);
    187     bool CreatePIP(PlayerContext*, const ProgramInfo *info);
    188     void ResizePIPWindow(PlayerContext*);
     183    bool CreatePBP(PlayerContext *lctx, const ProgramInfo *info);
     184    bool CreatePIP(PlayerContext *lctx, const ProgramInfo *info);
     185    bool ResizePIPWindow(PlayerContext*);
    189186    bool IsPIPSupported(const PlayerContext *ctx = NULL) const;
    190187
    191188    // Boolean queries
     
    237234                        bool inPlaylist = false, bool initByNetworkCommand = false);
    238235    static void SetFuncPtr(const char *, void *);
    239236
    240     void SetIgnoreKeys(bool ignore) { ignoreKeys = ignore; }
    241 
    242237    // Used by EPG
    243238    void ChangeVolume(PlayerContext*, bool up);
    244239    void ToggleMute(PlayerContext*);
    245240
    246     void WakeSetPIPPlayerCond(void);
    247     void SetNextProgPIPState(PIPState state) { nextProgPIPState = state; }
     241    void SetNextProgPIPState(PIPState state) { jumpToProgramPIPState = state; }
    248242
    249243    // Used for UDPNotify
    250244    bool HasUDPNotifyEvent(void) const;
     
    275269    static EMBEDRETURNVOID RunViewScheduledPtr;
    276270
    277271  private:
    278     void SetActive(PlayerContext *, int index);
     272    void SetActive(PlayerContext *lctx, int index, bool osd_msg);
    279273
    280274    PlayerContext       *GetPlayerWriteLock(
    281275        int which, const char *file, int location);
     
    296290
    297291    int  StartTimer(int interval, int line);
    298292    void KillTimer(int id);
    299     void ForceNextStateNone(PlayerContext*);
     293    void ForceNextStateNone(PlayerContext*, int line);
    300294    void ScheduleStateChange(PlayerContext*);
    301295    void SetErrored(PlayerContext*);
    302     void SetExitPlayer(bool set_it, bool wants_to) const;
     296    void SetExitPlayerReal(bool set_it, bool wants_to, int line) const;
    303297    void SetUpdateOSDPosition(bool set_it);
    304298
    305     bool PIPHandleAction(PlayerContext*,const QStringList &actions);
     299    bool PxPHandleAction(PlayerContext*,const QStringList &actions);
    306300    bool ToggleHandleAction(PlayerContext*,
    307301                            const QStringList &actions, bool isDVD);
    308302    bool FFRewHandleAction(PlayerContext*, const QStringList &actions);
    309303    bool ActivePostQHandleAction(PlayerContext*,
    310304                                 const QStringList &actions, bool isDVD);
     305    bool HandleJumpToProgramAction(PlayerContext *ctx,
     306                                   const QStringList   &actions);
    311307
    312308    bool RequestNextRecorder(PlayerContext *, bool);
    313309    void DeleteRecorder();
     
    421417                                const QStringList &actions);
    422418
    423419    void DoDisplayJumpMenu(void);
    424     void SetJumpToProgram(QString progKey = "", int progIndex = 0);
    425420 
    426421    bool ClearOSD(const PlayerContext*);
    427422    void ToggleOSD(const PlayerContext*, bool includeStatusOSD);
     
    441436                      int editType = kScheduleProgramGuide);
    442437
    443438    void TeardownPlayer(PlayerContext *mctx, PlayerContext *ctx);
    444     void TeardownPBP(PlayerContext*);
    445439
    446440    void HandleStateChange(PlayerContext *mctx, PlayerContext *ctx);
    447441
    448442    bool StartPlayer(PlayerContext *mctx, PlayerContext *ctx,
    449                      TVState desiredState, bool ispip = false);
    450     bool StartPIPPlayer(PlayerContext *mctx, PlayerContext *pipctx,
    451                         TVState desiredState);
    452     void SetPIPPlayer(PlayerContext *mctx, PlayerContext *pipctx);
    453     void TogglePIPView(PlayerContext*, bool ispbp = false);
    454     void ToggleActiveWindow(PlayerContext*, int ctx_index);
    455     void SwapPIP(PlayerContext *lctx, int ctx_index, bool ispbp);
    456     void TogglePIPState(PlayerContext*, PIPState changeTo);
    457     void RestartPIPWindows(PlayerContext *lctx, const vector<long long> &pos,
    458                            MuteState mctx_mute);
    459     void TeardownPIPWindows(PlayerContext*);
     443                     TVState desiredState);
    460444
     445    vector<long long> TeardownAllNVPs(PlayerContext*);
     446    void RestartAllNVPs(PlayerContext *lctx,
     447                        const vector<long long> &pos,
     448                        MuteState mctx_mute);
     449
     450    void PxPToggleView(  PlayerContext *actx, bool wantPBP);
     451    void PxPCreateView(  PlayerContext *actx, bool wantPBP);
     452    void PxPTeardownView(PlayerContext *actx);
     453    void PxPToggleType(  PlayerContext *mctx, bool wantPBP);
     454    void PxPSwap(        PlayerContext *mctx, int ctx_index = -1);
     455    bool HandlePxPTimerEvent(void);
     456
     457    bool PIPAddPlayer(   PlayerContext *mctx, PlayerContext *ctx);
     458    bool PIPRemovePlayer(PlayerContext *mctx, PlayerContext *ctx);
     459    void PBPRestartMainNVP(PlayerContext *mctx);
     460
    461461    void ToggleAutoExpire(PlayerContext*);
    462462
    463463    void BrowseStart(PlayerContext*);
     
    478478
    479479    void BuildOSDTreeMenu(const PlayerContext*);
    480480    void ShowOSDTreeMenu(const PlayerContext*);
     481    void FillMenuPxP(const PlayerContext*, OSDGenericTree *treeMenu,
     482                     bool freeRecorders);
    481483    void FillMenuLiveTV(OSDGenericTree *treeMenu);
    482484    void FillMenuPlaying(const PlayerContext*, OSDGenericTree *treeMenu);
    483485
     
    508510    void IdleDialogTimeout(void);
    509511
    510512    // Program jumping stuff
    511     void setLastProgram(ProgramInfo *rcinfo);
    512     ProgramInfo *getLastProgram(void) { return lastProgram; }
     513    void SetLastProgram(ProgramInfo *rcinfo);
     514    ProgramInfo *GetLastProgram(void) const;
    513515
    514516    static bool LoadExternalSubtitles(NuppelVideoPlayer *nvp,
    515517                                      const QString &videoFile);
     
    536538    QString db_time_format;
    537539    QString db_short_date_format;
    538540    uint    db_idle_timeout;
     541    uint    db_udpnotify_port;
     542    int     db_playback_exit_prompt;
     543    int     db_autoexpire_default;
    539544    bool    db_auto_set_watched;
    540545    bool    db_end_of_rec_exit_prompt;
     546    bool    db_jump_prefer_osd;
     547    bool    db_use_gui_size_for_tv;
     548    bool    db_start_in_guide;
     549    bool    db_toggle_bookmark;
     550    bool    db_run_jobs_on_remote;
     551    bool    db_use_dvd_bookmark;
     552    bool    db_continue_embedded;
     553    bool    db_use_fixed_size;
     554
    541555    bool    smartChannelChange;
    542556    bool    MuteIndividualChannels;
    543557    bool    arrowAccel;
     
    581595    QMap<QString,AskProgramInfo> askAllowPrograms;
    582596    QMutex                       askAllowLock;
    583597
    584     bool ignoreKeys;
    585     PIPState needToMakePIPChange;
    586     PIPState nextProgPIPState;
     598    MythDeque<QString> changePxP;
     599    QMutex progListsLock;
    587600    QMap<QString,ProgramList> progLists;
    588601
    589602    mutable QMutex chanEditMapLock; ///< Lock for chanEditMap and ddMap
     
    638651
    639652    // Program Info for currently playing video
    640653    // (or next video if InChangeState() is true)
     654    mutable QMutex lastProgramLock;
    641655    ProgramInfo *lastProgram;   ///< last program played with this player
    642     bool         jumpToProgram;
    643 
    644656    bool         inPlaylist; ///< show is part of a playlist
    645657    bool         underNetworkControl; ///< initial show started via by the network control interface
    646658    bool         isnearend;
    647659
     660    // Program Jumping
     661    PIPState     jumpToProgramPIPState;
     662    bool         jumpToProgram;
     663
    648664    // Video Players
    649665    vector<PlayerContext*>  player;
    650666    /// Video Player to which events are sent to
    651667    int                     playerActive;
    652668    /// lock on player and playerActive changes
    653669    mutable QReadWriteLock  playerLock;
    654     QWaitCondition pipPlayerSetCondition;
    655670
    656671    // Remote Encoders
    657672    /// Main recorder to use after a successful SwitchCards() call.
     
    740755    static const uint kInputKeysMax; ///< When to start discarding early keys
    741756    static const uint kNextSource;
    742757    static const uint kPreviousSource;
     758    static const uint kMaxPIPCount;
     759    static const uint kMaxPBPCount;
    743760
    744761    ///< Timeout for entry modes in msec
    745762    static const uint kInputModeTimeout;
  • libs/libmythtv/videoout_ivtv.h

     
    3232    void UpdatePauseFrame(void);
    3333    void ProcessFrame(VideoFrame *frame, OSD *osd,
    3434                      FilterChain *filterList,
    35                       NuppelVideoPlayer *pipPlayer);
     35                      const PIPMap &pipPlayers);
    3636
    3737    uint WriteBuffer(unsigned char *buf, int count);
    3838    int Poll(int delay);
     
    7777        kAlpha_Embedded
    7878    } eAlphaState;
    7979
    80     void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
     80    void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer, PIPLocation);
    8181    void SetAlpha(eAlphaState newAlpha);
    8282    void SetColorKey(int state, int color);
    8383    long long GetFirmwareFramesPlayed(void);
  • libs/libmythtv/playercontext.cpp

     
    3030}
    3131
    3232PlayerContext::PlayerContext() :
    33     nvp(NULL), recorder(NULL),
     33    nvp(NULL), nvpUnsafe(false), recorder(NULL),
    3434    tvchain(NULL), buffer(NULL), playingInfo(NULL),
    3535    decoding(false), last_cardid(-1), last_framerate(30.0f),
    3636    // Fast forward state
     
    102102        newPlaygroup = playingInfo->playgroup;
    103103    }
    104104
    105     ChangeState(newState);
     105    ChangeState(newState, __LINE__);
    106106    SetPlayGroup(newPlaygroup);
    107107}
    108108
     
    141141    if (pos > -1)
    142142    {
    143143        pipLocation = pos;
    144         name = QString("pip player %1")
    145                 .arg(PIPLocationToString());
     144        name = QString("pip player %1").arg(toString((PIPLocation)pos));
    146145    }
    147146    else
    148147        name = "pip player";
     
    216215    }
    217216}
    218217
    219 QString PlayerContext::PIPLocationToString(void)
    220 {
    221     QString pipstr = QString ("Unknown PIP Location %1").arg(pipLocation);
    222     switch (pipLocation)
    223     {
    224         case (kPIPTopLeft):
    225             pipstr = "PIP: Top Left";
    226             break;
    227         case (kPIPTopRight):
    228             pipstr = "PIP: Top Right";
    229             break;
    230         case (kPIPBottomLeft):
    231             pipstr = "PIP: Bottom Left";
    232             break;
    233         case (kPIPBottomRight):
    234             pipstr = "PIP: Bottom Right";
    235             break;
    236     }
    237 
    238     return pipstr;
    239 }
    240 
    241 QString PlayerContext::PIPStateToString(void)
    242 {
    243     QString pipstr = QString("Unknown PIP State %1").arg(pipState);
    244     switch (pipState)
    245     {
    246         case (kPIPOff):
    247             pipstr = "PIP is off";
    248             break;
    249         case (kPIPonTV):
    250             pipstr = "PIP is visible on TV";
    251             break;
    252         case (kPIPStandAlone):
    253             pipstr = "Standalone PIP";
    254             break;
    255         case (kPBPLeft):
    256             pipstr = "Left side Picture-by-Picture";
    257             break;
    258         case (kPBPRight):
    259             pipstr = "Right side Picture-by-Picture";
    260             break;
    261         case (kPIPToPBP):
    262             pipstr = "Preparing to switch from PIP to PBP";
    263             break;
    264         case (kPBPToPIP):
    265             pipstr = "Preparing to switch from PBP to PIP";
    266             break;
    267         case (kPBPToggle):
    268             pipstr = "Disabling PBP/PIP";
    269             break;
    270         case (kPIPSwap):
    271             pipstr = "Swapping PBP/PIP";
    272             break;
    273     }
    274 
    275     return pipstr;
    276 }
    277 
    278218bool PlayerContext::StartPIPPlayer(TV *tv, TVState desiredState)
    279219{
    280220    bool ok = false;
     
    440380        nvp->SetMuted(true);
    441381
    442382    int maxWait = -1;
    443     if (isPIP())
    444        maxWait = 1000;
     383    //if (isPIP())
     384    //   maxWait = 1000;
    445385
    446386    return StartDecoderThread(maxWait);
    447387}
     
    649589/**
    650590*   \brief Puts a state change on the nextState queue.
    651591*/
    652 void PlayerContext::ChangeState(TVState newState)
     592void PlayerContext::ChangeState(TVState newState, int line)
    653593{
     594    VERBOSE(VB_IMPORTANT, QString("ChangeState(%1,%2)")
     595            .arg(StateToString(newState)).arg(line));
    654596    QMutexLocker locker(&stateLock);
    655597    nextState.enqueue(newState);
    656598}
     
    664606/**
    665607 * \brief Removes any pending state changes, and puts kState_None on the queue.
    666608 */
    667 void PlayerContext::ForceNextStateNone(void)
     609void PlayerContext::ForceNextStateNone(int line)
    668610{
     611    VERBOSE(VB_IMPORTANT, QString("ForceNextStateNone(%2)").arg(line));
    669612    QMutexLocker locker(&stateLock);
    670613    nextState.clear();
    671614    nextState.push_back(kState_None);
  • libs/libmythtv/NuppelVideoPlayer.h

     
    149149    void SetVideoFilters(const QString &override);
    150150    void SetFramesPlayed(long long played)    { framesPlayed = played; }
    151151    void SetEof(void)                         { eof = true; }
    152     void SetPIPPlayer(NuppelVideoPlayer *pip)
    153         { setpipplayer = pip; needsetpipplayer = true; }
     152    void SetPIPActive(bool is_active)         { pip_active = is_active; }
     153    bool AddPIPPlayer(NuppelVideoPlayer *pip, PIPLocation loc, uint timeout);
     154    bool RemovePIPPlayer(NuppelVideoPlayer *pip, uint timeout);
    154155
    155156    void SetTranscoding(bool value);
    156157    void SetWatchingRecording(bool mode);
     
    203204    QString   GetXDS(const QString &key) const;
    204205    QString   GetErrorMsg(void) const { return errmsg; }
    205206    bool      GetAudioBufferStatus(uint &fill, uint &total) const;
     207    PIPLocation GetNextPIPLocation(void) const;
    206208
    207209    // Bool Gets
    208210    bool    GetRawAudioState(void) const;
    209211    bool    GetLimitKeyRepeat(void) const     { return limitKeyRepeat; }
    210212    bool    GetEof(void) const                { return eof; }
    211     bool    PipPlayerSet(void) const          { return !needsetpipplayer; }
    212213    bool    IsErrored(void) const             { return errored; }
    213214    bool    IsPlaying(uint wait_ms = 0, bool wait_for = true) const;
    214215    bool    AtNormalSpeed(void) const         { return next_normal_speed; }
     
    218219    bool    PlayingSlowForPrebuffer(void) const { return m_playing_slower; }
    219220    bool    HasAudioIn(void) const            { return !no_audio_in; }
    220221    bool    HasAudioOut(void) const           { return !no_audio_out; }
     222    bool    IsPIPActive(void) const           { return pip_active; }
    221223    bool    IsMuted(void) const        { return GetMuteState() == kMuteAll; }
    222224    bool    IsIVTVDecoder(void) const;
    223225    bool    UsingNullVideo(void) const { return using_null_videoout; }
     
    530532    long long GetDVDBookmark(void) const;
    531533    void SetDVDBookmark(long long frames);
    532534
     535    // Private PIP stuff
     536    void HandlePIPPlayerLists(uint max_pip_players);
     537
    533538  private:
    534539    DecoderBase   *decoder;
    535540    QMutex         decoder_change_lock;
     
    702707    bool     audio_passthru;
    703708
    704709    // Picture-in-Picture
    705     NuppelVideoPlayer *pipplayer;
    706     NuppelVideoPlayer *setpipplayer;
    707     bool needsetpipplayer;
     710    mutable QMutex pip_players_lock;
     711    QWaitCondition pip_players_wait;
     712    PIPMap         pip_players;
     713    PIPMap         pip_players_add;
     714    PIPMap         pip_players_rm;
     715    volatile bool  pip_active;
    708716
    709717    // Preview window support
    710718    unsigned char      *argb_buf;
  • libs/libmythtv/tv_play.cpp

     
    6565
    6666#define GetPlayer(X,Y) GetPlayerHaveLock(X, Y, __FILE__ , __LINE__)
    6767#define GetOSDLock(X) GetOSDL(X, __FILE__, __LINE__)
     68#define SetExitPlayer(X,Y) SetExitPlayerReal(X,Y,__LINE__)
    6869
    6970const int  TV::kInitFFRWSpeed                = 0;
    7071const uint TV::kInputKeysMax                 = 6;
    7172const uint TV::kNextSource                   = 1;
    7273const uint TV::kPreviousSource               = 2;
     74const uint TV::kMaxPIPCount                  = 4;
     75const uint TV::kMaxPBPCount                  = 2;
    7376
     77
    7478const uint TV::kInputModeTimeout             = 5000;
    7579const uint TV::kMuteTimeout                  = 800;
    7680const uint TV::kLCDTimeout                   = 1000;
     
    154158    if (!lastProgramStringList.empty())
    155159    {
    156160        ProgramInfo *p = new ProgramInfo();
    157         p->FromStringList(lastProgramStringList, 0);
    158         tv->setLastProgram(p);
     161        if (p->FromStringList(lastProgramStringList, 0))
     162            tv->SetLastProgram(p);
    159163        delete p;
    160164    }
    161165
     
    175179            VERBOSE(VB_PLAYBACK, LOC + "tv->LiveTV() -- begin");
    176180            if (!tv->LiveTV(showDialogs, startInGuide))
    177181            {
    178                 tv->StopLiveTV();
     182                tv->SetExitPlayerReal(true, true, __LINE__);
    179183                quitAll = true;
    180184            }
    181185            VERBOSE(VB_PLAYBACK, LOC + "tv->LiveTV() -- end");
     
    270274
    271275        if (tv->getJumpToProgram())
    272276        {
     277            ProgramInfo *nextProgram = tv->GetLastProgram();
    273278
    274             ProgramInfo *tmpProgram  = tv->getLastProgram();
    275             ProgramInfo *nextProgram = new ProgramInfo(*tmpProgram);
    276 
     279            tv->SetLastProgram(curProgram);
    277280            if (curProgram)
    278             {
    279                 tv->setLastProgram(curProgram);
    280281                delete curProgram;
    281             }
    282             else
    283                 tv->setLastProgram(NULL);
    284282
    285283            curProgram = nextProgram;
    286284
     
    420418    REG_KEY("TV Playback", "VOLUMEDOWN", "Volume down", "[,{,F10,Volume Down");
    421419    REG_KEY("TV Playback", "VOLUMEUP",   "Volume up",   "],},F11,Volume Up");
    422420    REG_KEY("TV Playback", "MUTE",       "Mute",        "|,\\,F9,Volume Mute");
    423     REG_KEY("TV Playback", "TOGGLEPIPMODE", "Toggle Picture-in-Picture mode",
     421    REG_KEY("TV Playback", "TOGGLEPIPMODE", "Toggle Picture-in-Picture view",
    424422            "V");
    425     REG_KEY("TV Playback", "TOGGLEPBPMODE", "Toggle Picture-by-Picture mode",
     423    REG_KEY("TV Playback", "TOGGLEPBPMODE", "Toggle Picture-by-Picture view",
    426424            "Ctrl+V");
    427     REG_KEY("TV Playback", "TOGGLEPIPWINDOW", "Toggle active PIP/PBP window", "B");
     425    REG_KEY("TV Playback", "CREATEPIPVIEW", "Create Picture-in-Picture view",
     426            "1");
     427    REG_KEY("TV Playback", "CREATEPBPVIEW", "Create Picture-by-Picture view",
     428            "Ctrl+1");
     429    REG_KEY("TV Playback", "NEXTPIPWINDOW", "Toggle active PIP/PBP window", "B");
    428430    REG_KEY("TV Playback", "SWAPPIP", "Swap PBP/PIP Windows", "N");
    429     REG_KEY("TV Playback", "TOGGLEPIPSTATE", "Change PIP from PBP or visa versa"
    430             ,"");
     431    REG_KEY("TV Playback", "TOGGLEPIPSTATE", "Change PxP view", "");
    431432    REG_KEY("TV Playback", "TOGGLEASPECT",
    432433            "Toggle the video aspect ratio", "Ctrl+W");
    433434    REG_KEY("TV Playback", "TOGGLEFILL", "Next Preconfigured Zoom mode", "W");
     
    569570      baseFilters(""),
    570571      db_channel_format("<num> <sign>"),
    571572      db_time_format("h:mm AP"), db_short_date_format("M/d"),
    572       db_idle_timeout(0),
    573       db_auto_set_watched(false),
    574       db_end_of_rec_exit_prompt(false),
     573      db_idle_timeout(0),           db_udpnotify_port(0),
     574      db_playback_exit_prompt(0),   db_autoexpire_default(0),
     575      db_auto_set_watched(false),   db_end_of_rec_exit_prompt(false),
     576      db_jump_prefer_osd(true),     db_use_gui_size_for_tv(false),
     577      db_start_in_guide(false),     db_toggle_bookmark(false),
     578      db_run_jobs_on_remote(false), db_use_dvd_bookmark(false),
     579      db_continue_embedded(false),  db_use_fixed_size(true),
     580
    575581      smartChannelChange(false),
    576582      MuteIndividualChannels(false), arrowAccel(false),
    577583      osd_general_timeout(2), osd_prog_info_timeout(3),
     
    594600      adjustingPicture(kAdjustingPicture_None),
    595601      adjustingPictureAttribute(kPictureAttribute_None),
    596602      askAllowType(kAskAllowCancel), askAllowLock(QMutex::Recursive),
    597       ignoreKeys(false),
    598       needToMakePIPChange(kPIPOff),
    599       nextProgPIPState(kPIPOff),
    600603      // Channel Editing
    601604      chanEditMapLock(QMutex::Recursive),
    602605      ddMapSourceId(0), ddMapLoaderRunning(false),
     
    615618      browsemode(false), persistentbrowsemode(false),
    616619      browsechannum(""), browsechanid(""), browsestarttime(""),
    617620      // Program Info for currently playing video
    618       lastProgram(NULL), jumpToProgram(false),
     621      lastProgram(NULL),
    619622      inPlaylist(false), underNetworkControl(false),
    620623      isnearend(false),
     624      // Jump to program stuff
     625      jumpToProgramPIPState(kPIPOff),
     626      jumpToProgram(false),
    621627      // Video Player currently receiving UI input
    622628      playerActive(-1),
    623629      //Recorder switching info
     
    647653
    648654    db_idle_timeout = gContext->GetNumSetting("LiveTVIdleTimeout", 0);
    649655    db_idle_timeout *= 60 * 1000; // convert from minutes to ms.
    650     db_auto_set_watched = gContext->GetNumSetting("AutomaticSetWatched", 0);
     656    db_udpnotify_port      = gContext->GetNumSetting("UDPNotifyPort", 0);
     657    db_playback_exit_prompt= gContext->GetNumSetting("PlaybackExitPrompt", 0);
     658    db_autoexpire_default  = gContext->GetNumSetting("AutoExpireDefault", 0);
     659
     660    db_auto_set_watched     = gContext->GetNumSetting("AutomaticSetWatched", 0);
    651661    db_end_of_rec_exit_prompt =
    652662        gContext->GetNumSetting("EndOfRecordingExitPrompt", 0);
     663    db_jump_prefer_osd     = gContext->GetNumSetting("JumpToProgramOSD", 1);
     664    db_use_gui_size_for_tv = gContext->GetNumSetting("GuiSizeForTV", 0);
     665    db_start_in_guide      = gContext->GetNumSetting("WatchTVGuide", 0);
     666    db_toggle_bookmark     = gContext->GetNumSetting("AltClearSavedPosition",1);
     667    db_run_jobs_on_remote  = gContext->GetNumSetting("JobsRunOnRecordHost", 0);
     668    db_use_dvd_bookmark    = gContext->GetNumSetting("EnableDVDBookmark", 0);
     669    db_continue_embedded   = gContext->GetNumSetting(
     670        "ContinueEmbeddedTVPlay", 0);
     671    db_use_fixed_size      = gContext->GetNumSettingOnHost(
     672        "UseFixedWindowSize", gContext->GetHostName(), 1);
    653673
    654674    sleep_times.push_back(SleepTimerInfo(QObject::tr("Off"),       0));
    655675    sleep_times.push_back(SleepTimerInfo(QObject::tr("30m"),   30*60));
     
    662682
    663683    playerLock.lockForWrite();
    664684    player.push_back(new PlayerContext());
     685    playerActive = 0;
    665686    playerLock.unlock();
    666     SetActive(NULL, 0);
    667687}
    668688
    669689/** \fn TV::Init(bool)
     
    768788            }
    769789        }
    770790
    771         bool use_fixed_size = gContext->GetNumSettingOnHost(
    772             "UseFixedWindowSize", gContext->GetHostName(), 1);
    773 
    774791        // player window sizing
    775792        myWindow = new MythDialog(mainWindow, "video playback window");
    776793
     
    780797        myWindow->setGeometry(win_bounds);
    781798        myWindow->setBaseSize(win_bounds.size());
    782799        myWindow->setMinimumSize(
    783             (use_fixed_size) ? win_bounds.size() : QSize(16, 16));
     800            (db_use_fixed_size) ? win_bounds.size() : QSize(16, 16));
    784801        myWindow->setMaximumSize(
    785             (use_fixed_size) ? win_bounds.size() :
     802            (db_use_fixed_size) ? win_bounds.size() :
    786803            QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
    787804
    788805        // resize main window
    789806        mainWindow->setGeometry(player_bounds);
    790807        mainWindow->setBaseSize(player_bounds.size());
    791808        mainWindow->setMinimumSize(
    792             (use_fixed_size) ? player_bounds.size() : QSize(16, 16));
     809            (db_use_fixed_size) ? player_bounds.size() : QSize(16, 16));
    793810        mainWindow->setMaximumSize(
    794             (use_fixed_size) ? player_bounds.size() :
     811            (db_use_fixed_size) ? player_bounds.size() :
    795812            QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
    796813        mainWindow->installEventFilter(this);
    797814
     
    834851        mwnd->resize(saved_gui_bounds.size());
    835852        mwnd->setFixedSize(saved_gui_bounds.size());
    836853        mwnd->show();
    837         if (!gContext->GetNumSetting("GuiSizeForTV", 0))
     854        if (!db_use_gui_size_for_tv)
    838855            mwnd->move(saved_gui_bounds.topLeft());
    839856    }
    840857
     
    923940                    .arg(db_idle_timeout*(1.0f/60000.0f)));
    924941        }
    925942
    926         if (startInGuide || gContext->GetNumSetting("WatchTVGuide", 0))
     943        if (startInGuide || db_start_in_guide)
    927944        {
    928945            MSqlQuery query(MSqlQuery::InitCon());
    929946            query.prepare("SELECT keylist FROM keybindings WHERE "
     
    13361353                break;
    13371354            case 2:
    13381355                // return to main menu
    1339                 StopLiveTV();
     1356                SetExitPlayer(true, true);
    13401357                break;
    13411358            case 3:
    13421359                // cancel scheduled recording
     
    13531370            default:
    13541371            case 1:
    13551372                // return to main menu
    1356                 StopLiveTV();
     1373                SetExitPlayer(true, true);
    13571374                break;
    13581375            case 2:
    13591376            {
     
    16281645        {
    16291646            // Cache starting frame rate for this recorder
    16301647            ctx->last_framerate = ctx->recorder->GetFrameRate();
    1631             ok = StartPlayer(mctx, ctx, desiredNextState, ctx->isPIP());
     1648            ok = StartPlayer(mctx, ctx, desiredNextState);
    16321649        }
    16331650        if (!ok)
    16341651        {
     
    16481665                lockTimerOn = true;
    16491666            }
    16501667        }
     1668
     1669        if (mctx != ctx)
     1670            SetActive(ctx, find_player_index(ctx), false);
    16511671    }
    16521672    else if (TRANSITION(kState_WatchingLiveTV, kState_None))
    16531673    {
    16541674        SET_NEXT();
    16551675        RestoreScreenSaver(ctx);
    16561676        StopStuff(mctx, ctx, true, true, true);
     1677
     1678        if ((mctx != ctx) && (GetPlayer(ctx,-1) == ctx))
     1679            SetActive(mctx, 0, true);
    16571680    }
    16581681    else if (TRANSITION(kState_WatchingRecording, kState_WatchingPreRecorded))
    16591682    {
     
    17041727                }
    17051728            }
    17061729
    1707             ok = StartPlayer(mctx, ctx, desiredNextState, ctx->isPIP());
     1730            ok = StartPlayer(mctx, ctx, desiredNextState);
    17081731
    17091732            if (ok)
    17101733            {
     
    17271750            SET_LAST();
    17281751            SetErrored(ctx);
    17291752        }
     1753        else if (mctx != ctx)
     1754        {
     1755            SetActive(ctx, find_player_index(ctx), false);
     1756        }
    17301757    }
    17311758    else if (TRANSITION(kState_WatchingPreRecorded, kState_None) ||
    17321759             TRANSITION(kState_WatchingRecording, kState_None))
     
    17351762
    17361763        RestoreScreenSaver(ctx);
    17371764        StopStuff(mctx, ctx, true, true, false);
     1765
     1766        if ((mctx != ctx) && (GetPlayer(ctx,-1) == ctx))
     1767            SetActive(mctx, 0, true);
    17381768    }
    17391769    else if (TRANSITION(kState_None, kState_None))
    17401770    {
     
    17541784
    17551785        nextState = kState_None;
    17561786        changed = true;
     1787
     1788        if ((mctx != ctx) && (GetPlayer(ctx,-1) == ctx))
     1789            SetActive(mctx, 0, true);
    17571790    }
    17581791
    17591792    // Print state changed message...
     
    19011934            LOC + QString("StopStuff() for player ctx %1 -- begin")
    19021935            .arg(find_player_index(ctx)));
    19031936
    1904     SetActive(mctx, 0);
     1937    SetActive(mctx, 0, false);
    19051938
    19061939    if (ctx->buffer && ctx->buffer->isDVD())
    19071940    {
     
    19511984    QString loc = LOC + QString("TeardownPlayer() player ctx %1")
    19521985        .arg(ctx_index);
    19531986
    1954     SetActive(mctx, 0);
     1987    if (!mctx || !ctx || ctx_index < 0)
     1988    {
     1989        VERBOSE(VB_IMPORTANT, loc + "-- error");
     1990        return;
     1991    }
    19551992
     1993    VERBOSE(VB_PLAYBACK, loc);
     1994
    19561995    if (mctx != ctx)
    19571996    {
    19581997        if (ctx->nvp)
    19591998        {
     1999            PIPRemovePlayer(mctx, ctx);
    19602000            ctx->nvp->StopPlaying();
    19612001            ctx->SetNVP(NULL);
    19622002        }
    19632003
    1964         SetPIPPlayer(mctx, ctx);
    19652004        player.erase(player.begin() + ctx_index);
    19662005        delete ctx;
    1967         TeardownPBP(ctx);
     2006        PBPRestartMainNVP(mctx);
     2007        SetActive(mctx, playerActive, false);
    19682008        return;
    19692009    }
    19702010
     
    20222062    mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
    20232063    if (!mctx->IsErrored() && (GetState(mctx) != kState_None))
    20242064    {
    2025         mctx->ForceNextStateNone();
     2065        mctx->ForceNextStateNone(__LINE__);
    20262066        HandleStateChange(mctx, mctx);
    20272067        if (jumpToProgram)
    20282068            TeardownPlayer(mctx, mctx);
     
    20762116        HandlePseudoLiveTVTimerEvent();
    20772117    else if (timer_id == speedChangeTimerId)
    20782118        HandleSpeedChangeTimerEvent();
     2119    else if (timer_id == pipChangeTimerId)
     2120        HandlePxPTimerEvent();
    20792121    else
    20802122        handled = false;
    20812123
     
    22752317
    22762318    // Check if it matches networkControlTimerId
    22772319    QString netCmd = QString::null;
    2278     if (!ignoreKeys)
    22792320    {
    22802321        QMutexLocker locker(&timerIdLock);
    22812322        if (timer_id == networkControlTimerId)
     
    22922333
    22932334    if (!netCmd.isEmpty())
    22942335    {
    2295         PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     2336        PlayerContext *actx = GetPlayerWriteLock(-1, __FILE__, __LINE__);
    22962337        ProcessNetworkControlCommand(actx, netCmd);
    22972338        ReturnPlayerLock(actx);
    22982339        handled = true;
     
    23292370                }
    23302371                ReturnOSDLock(mctx, osd);
    23312372                lastProgramStringList.clear();
    2332                 setLastProgram(NULL);
     2373                SetLastProgram(NULL);
    23332374                VERBOSE(VB_PLAYBACK, LOC_ERR +
    23342375                            "Last Program File does not exist");
    23352376                jumpToProgram = false;
    23362377            }
    23372378            else
    2338                 ForceNextStateNone(mctx);
     2379                ForceNextStateNone(mctx, __LINE__);
    23392380        }
    23402381        else
    2341             ForceNextStateNone(mctx);
     2382            ForceNextStateNone(mctx, __LINE__);
    23422383
    23432384        ReturnPlayerLock(mctx);
    23442385
     
    23642405    if (handled)
    23652406        return;
    23662407
    2367     if (timer_id == pipChangeTimerId)
    2368     {
    2369         if (needToMakePIPChange > kPIPOff)
    2370         {
    2371             PlayerContext *mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
    2372             ClearOSD(mctx);
    2373 
    2374             switch (needToMakePIPChange)
    2375             {
    2376                 case (kPIPSwap):
    2377                     SwapPIP(mctx, 1, false);
    2378                     break;
    2379                 case (kPBPSwap):
    2380                     SwapPIP(mctx, 1, true);
    2381                     break;
    2382                 case (kPIPToPBP):
    2383                     TogglePIPState(mctx, needToMakePIPChange);
    2384                     break;
    2385                 case (kPBPToPIP):
    2386                     TogglePIPState(mctx, needToMakePIPChange);
    2387                     break;
    2388                 case (kPBPToggle):
    2389                 {
    2390                     if (mctx && (player.size() > 1))
    2391                         TeardownPlayer(mctx, GetPlayer(mctx, 1));
    2392                     else
    2393                         TogglePIPView(mctx, true);
    2394                     break;
    2395                 }
    2396             }
    2397             ReturnPlayerLock(mctx);
    2398 
    2399             needToMakePIPChange = kPIPOff;
    2400         }
    2401 
    2402         QMutexLocker locker(&timerIdLock);
    2403         if (pipChangeTimerId)
    2404             KillTimer(pipChangeTimerId);
    2405         pipChangeTimerId = 0;
    2406         handled = true;
    2407     }
    2408 
    2409     if (handled)
    2410         return;
    2411 
    24122408    if (timer_id == udpNotifyTimerId)
    24132409    {
    24142410        while (HasUDPNotifyEvent())
     
    25552551    {
    25562552        PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    25572553        OSD *osd = GetOSDLock(actx);
    2558         OSDSet *oset = osd->GetSet("status");
     2554        OSDSet *oset = NULL;
     2555        if (osd)
     2556            oset = osd->GetSet("status");
    25592557        if (osd && oset && oset->Displaying() &&
    25602558            (StateIsLiveTV(actx->GetState()) ||
    25612559             StateIsPlaying(actx->GetState())))
     
    25802578            (mctx->nvp && mctx->nvp->IsErrored()) || mctx->IsErrored())
    25812579        {
    25822580            SetExitPlayer(true, false);
    2583             ForceNextStateNone(mctx);
     2581            ForceNextStateNone(mctx, __LINE__);
    25842582            error = true;
    25852583        }
    25862584
     
    25882586        {
    25892587            PlayerContext *ctx = GetPlayer(mctx, i);
    25902588            if (error || ctx->IsErrored())
    2591                 ForceNextStateNone(ctx);
     2589                ForceNextStateNone(ctx, __LINE__);
    25922590        }
    25932591        ReturnPlayerLock(mctx);
    25942592
     
    26002598    }
    26012599}
    26022600
     2601bool TV::HandlePxPTimerEvent(void)
     2602{
     2603    QString cmd = QString::null;
     2604
     2605    {
     2606        QMutexLocker locker(&timerIdLock);
     2607        if (changePxP.empty())
     2608        {
     2609            if (pipChangeTimerId)
     2610                KillTimer(pipChangeTimerId);
     2611            pipChangeTimerId = 0;
     2612            return true;
     2613        }
     2614        cmd = changePxP.dequeue();
     2615    }
     2616
     2617    PlayerContext *mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
     2618    PlayerContext *actx = GetPlayer(mctx, -1);
     2619
     2620    if (cmd == "TOGGLEPIPMODE")
     2621        PxPToggleView(actx, false);
     2622    else if (cmd == "TOGGLEPBPMODE")
     2623        PxPToggleView(actx, true);
     2624    else if (cmd == "CREATEPIPVIEW")
     2625        PxPCreateView(actx, false);
     2626    else if (cmd == "CREATEPBPVIEW")
     2627        PxPCreateView(actx, true);
     2628    else if (cmd == "SWAPPIP")
     2629        PxPSwap(mctx);
     2630    else if (cmd == "TOGGLEPIPSTATE")
     2631        PxPToggleType(mctx, !mctx->isPBP());
     2632
     2633    ReturnPlayerLock(mctx);
     2634
     2635    QMutexLocker locker(&timerIdLock);
     2636
     2637    if (pipChangeTimerId)
     2638        KillTimer(pipChangeTimerId);
     2639
     2640    if (changePxP.empty())
     2641        pipChangeTimerId = 0;
     2642    else
     2643        pipChangeTimerId = StartTimer(20, __LINE__);
     2644
     2645    return true;
     2646}
     2647
    26032648bool TV::HandleLCDTimerEvent(void)
    26042649{
    26052650    PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     
    26542699    QObject::killTimer(id);
    26552700}
    26562701
    2657 void TV::ForceNextStateNone(PlayerContext *ctx)
     2702void TV::ForceNextStateNone(PlayerContext *ctx, int line)
    26582703{
    2659     ctx->ForceNextStateNone();
     2704    ctx->ForceNextStateNone(line);
    26602705    ScheduleStateChange(ctx);
    26612706}
    26622707
     
    26742719    errorRecoveryTimerId = StartTimer(1, __LINE__);
    26752720}
    26762721
    2677 void TV::SetExitPlayer(bool set_it, bool wants_to) const
     2722void TV::SetExitPlayerReal(bool set_it, bool wants_to, int line) const
    26782723{
     2724    VERBOSE(VB_IMPORTANT,
     2725            LOC + "SetExitPlayer("<<set_it<<","<<wants_to<<","<<line<<")");
     2726
    26792727    QMutexLocker locker(&timerIdLock);
    26802728    if (set_it)
    26812729    {
     
    27312779            continue;
    27322780        }
    27332781
    2734         ForceNextStateNone(ctx);
     2782        ForceNextStateNone(ctx, __LINE__);
    27352783        if (mctx == ctx)
    27362784        {
    27372785            endOfRecording = true;
     
    30653113
    30663114void TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e)
    30673115{
     3116    bool ignoreKeys = actx->IsNVPChangingBuffers();
    30683117#if DEBUG_ACTIONS
    3069     VERBOSE(VB_IMPORTANT, LOC + "ProcessKeypress() ignoreKeys: "<<ignoreKeys);
     3118    VERBOSE(VB_IMPORTANT, LOC + QString("ProcessKeypress() ignoreKeys: %1")
     3119            .arg(ignoreKeys));
    30703120#endif // DEBUG_ACTIONS
    30713121
    30723122    if (db_idle_timeout > 0)
     
    31913241    handled = handled || DVDMenuHandleAction(actx, actions, isDVD, isDVDStill);
    31923242    handled = handled || ActiveHandleAction(actx, actions, isDVD, isDVDStill);
    31933243    handled = handled || ToggleHandleAction(actx, actions, isDVD);
    3194     handled = handled || PIPHandleAction(actx, actions);
     3244    handled = handled || PxPHandleAction(actx, actions);
    31953245    handled = handled || FFRewHandleAction(actx, actions);
    31963246    handled = handled || ActivePostQHandleAction(actx, actions, isDVD);
    31973247
     
    32233273
    32243274bool TV::BrowseHandleAction(PlayerContext *ctx, const QStringList &actions)
    32253275{
    3226     bool handled = false;
    32273276    if (!browsemode)
    3228         return handled;
     3277        return false;
    32293278
    3230     handled = true;
     3279    bool handled = true;
    32313280
    32323281    if (has_action("UP", actions) || has_action("CHANNELUP", actions))
    32333282        BrowseDispInfo(ctx, BROWSE_UP);
     
    32543303        ToggleRecord(ctx);
    32553304    else
    32563305    {
     3306        handled = false;
    32573307        QStringList::const_iterator it = actions.begin();
    32583308        for (; it != actions.end(); ++it)
    32593309        {
     
    32623312            {
    32633313                CommitQueuedInput(ctx);
    32643314                BrowseEnd(ctx, false);
     3315                handled = true;
    32653316            }
    32663317        }
    32673318    }
    32683319
    32693320    // only pass-through actions listed below
    3270     return !(has_action("VOLUMEDOWN",      actions) ||
    3271              has_action("VOLUMEUP",        actions) ||
    3272              has_action("STRETCHINC",      actions) ||
    3273              has_action("STRETCHDEC",      actions) ||
    3274              has_action("MUTE",            actions) ||
    3275              has_action("TOGGLEASPECT",    actions) ||
    3276              has_action("TOGGLEPIPWINDOW", actions) ||
    3277              has_action("TOGGLEPIPMODE",   actions) ||
    3278              has_action("TOGGLEPIPSTATE",  actions) ||
    3279              has_action("SWAPPIP",         actions));
    3280 
    3281     // TODO FIXME this is never reached.. must be a logic error
    3282     return handled;
     3321    return handled ||
     3322        !(has_action("VOLUMEDOWN",      actions) ||
     3323          has_action("VOLUMEUP",        actions) ||
     3324          has_action("STRETCHINC",      actions) ||
     3325          has_action("STRETCHDEC",      actions) ||
     3326          has_action("MUTE",            actions) ||
     3327          has_action("TOGGLEASPECT",    actions) ||
     3328          has_action("TOGGLEPIPMODE",   actions) ||
     3329          has_action("TOGGLEPIPSTATE",  actions) ||
     3330          has_action("NEXTPIPWINDOW",   actions) ||
     3331          has_action("CREATEPIPVIEW",   actions) ||
     3332          has_action("CREATEPBPVIEW",   actions) ||
     3333          has_action("SWAPPIP",         actions));
    32833334}
    32843335
    32853336bool TV::ManualZoomHandleAction(PlayerContext *actx, const QStringList &actions)
     
    34673518        }
    34683519        else if (dialogname == "allowrecordingbox")
    34693520        {
    3470             int result = osd->GetDialogResponse(dialogname);
    3471 
    3472             if (result == 1)
    3473                 actx->recorder->CancelNextRecording(false);
    3474             else if (result == 2)
    3475                 StopLiveTV();
    3476             else if (result == 3)
    3477                 actx->recorder->CancelNextRecording(true);
     3521            HandleOSDAskAllowResponse();
    34783522        }
    34793523        else if (dialogname == "idletimeout")
    34803524        {
     
    38313875    {
    38323876        ClearOSD(ctx);
    38333877    }
    3834     else if (has_action("JUMPPREV", actions))
    3835     {
    3836         if (PromptRecGroupPassword(ctx))
    3837         {
    3838             ctx->nvp->SetBookmark();
    3839             SetExitPlayer(true, true);
    3840         }
    3841     }
    38423878    else if (has_action("VIEWSCHEDULED", actions))
    38433879        EditSchedule(ctx, kViewSchedule);
    3844     else if (has_action("JUMPREC", actions))
     3880    else if (HandleJumpToProgramAction(ctx, actions))
    38453881    {
    3846         if (gContext->GetNumSetting("JumpToProgramOSD", 1) &&
    3847             StateIsPlaying(ctx->GetState()))
    3848         {
    3849             if (jumpMenuTimerId)
    3850                 KillTimer(jumpMenuTimerId);
    3851             jumpMenuTimerId = StartTimer(1, __LINE__);
    3852         }
    3853         else if (RunPlaybackBoxPtr)
    3854             EditSchedule(ctx, kPlaybackBox);
    38553882    }
    38563883    else if (has_action("SIGNALMON", actions))
    38573884    {
     
    38983925    }
    38993926    else if (has_action("ESCAPE", actions))
    39003927    {
    3901         SetActive(ctx, 0);
     3928        VERBOSE(VB_IMPORTANT, LOC + "ESCAPE");
     3929
    39023930        osd = GetOSDLock(ctx);
    39033931        if (StateIsLiveTV(ctx->GetState()) &&
    39043932            (ctx->lastSignalMsgTime.elapsed() <
     
    39173945
    39183946        StopFFRew(ctx);
    39193947
     3948        bool do_exit = false;
     3949
    39203950        if (StateIsLiveTV(GetState(ctx)))
    39213951        {
    39223952            if (ctx->nvp &&
    3923                 (12 & gContext->GetNumSetting("PlaybackExitPrompt")))
     3953                (12 & db_playback_exit_prompt))
    39243954            {
    39253955                PromptStopWatchingRecording(ctx);
    39263956            }
    39273957            else
    39283958            {
    3929                 SetExitPlayer(true, true);
     3959                do_exit = true;
    39303960            }
    39313961        }
    39323962        else
    39333963        {
    39343964            if (ctx->nvp &&
    3935                 (5 & gContext->GetNumSetting("PlaybackExitPrompt")) &&
     3965                (5 & db_playback_exit_prompt) &&
    39363966                !underNetworkControl && !isDVDStill)
    39373967            {
    39383968                PromptStopWatchingRecording(ctx);
    39393969                return handled;
    39403970            }
    39413971            else if (ctx->nvp &&
    3942                      (gContext->GetNumSetting("PlaybackExitPrompt") == 2))
     3972                     (db_playback_exit_prompt == 2))
    39433973            {
    39443974                ctx->nvp->SetBookmark();
    39453975            }
    39463976            if (ctx->nvp &&
    3947                 gContext->GetNumSetting("AutomaticSetWatched", 0))
     3977                db_auto_set_watched)
    39483978            {
    39493979                ctx->nvp->SetWatched();
    39503980            }
    39513981            requestDelete = false;
    3952             SetExitPlayer(true, true);
     3982            do_exit = true;
    39533983        }
     3984
     3985        if (do_exit)
     3986        {
     3987            PlayerContext *mctx = GetPlayer(ctx, 0);
     3988            if (mctx != ctx)
     3989            { // A PIP is active, just tear it down..
     3990                PxPTeardownView(ctx);
     3991                return handled;
     3992            }
     3993            else
     3994            {
     3995                SetExitPlayer(true, true);
     3996            }
     3997        }
     3998
     3999        SetActive(ctx, 0, false);
    39544000    }
    39554001    else if (has_action("VOLUMEDOWN", actions))
    39564002        ChangeVolume(ctx, false);
     
    40754121    return handled;
    40764122}
    40774123
    4078 bool TV::PIPHandleAction(PlayerContext *ctx, const QStringList &actions)
     4124bool TV::PxPHandleAction(PlayerContext *ctx, const QStringList &actions)
    40794125{
    4080     bool handled = true;
    4081 
    40824126    if (!IsPIPSupported(ctx))
    4083         return handled;
     4127        return false;
    40844128
    4085     if (has_action("TOGGLEPIPMODE", actions))
    4086         TogglePIPView(ctx);
    4087     else if (has_action("TOGGLEPBPMODE", actions))
     4129    bool handled = true;
    40884130    {
    4089         needToMakePIPChange = kPBPToggle;
    4090         if (pipChangeTimerId)
    4091             KillTimer(pipChangeTimerId);
    4092         pipChangeTimerId = StartTimer(1, __LINE__);
     4131        QMutexLocker locker(&timerIdLock);
     4132
     4133        if (has_action("TOGGLEPIPMODE", actions))
     4134            changePxP.enqueue("TOGGLEPIPMODE");
     4135        else if (has_action("TOGGLEPBPMODE", actions))
     4136            changePxP.enqueue("TOGGLEPBPMODE");
     4137        else if (has_action("CREATEPIPVIEW", actions))
     4138            changePxP.enqueue("CREATEPIPVIEW");
     4139        else if (has_action("CREATEPBPVIEW", actions))
     4140            changePxP.enqueue("CREATEPBPVIEW");
     4141        else if (has_action("SWAPPIP", actions))
     4142            changePxP.enqueue("SWAPPIP");
     4143        else if (has_action("TOGGLEPIPSTATE", actions))
     4144            changePxP.enqueue("TOGGLEPIPSTATE");
     4145        else
     4146            handled = false;
     4147       
     4148        if (!changePxP.empty() && !pipChangeTimerId)
     4149            pipChangeTimerId = StartTimer(1, __LINE__);
    40934150    }
    4094     else if (has_action("SWAPPIP", actions))
     4151
     4152    if (has_action("NEXTPIPWINDOW", actions))
    40954153    {
    4096         needToMakePIPChange = (ctx->isPBP()) ? kPBPSwap : kPIPSwap;
    4097         if (pipChangeTimerId)
    4098             KillTimer(pipChangeTimerId);
    4099         pipChangeTimerId = StartTimer(1, __LINE__);
     4154        SetActive(ctx, -1, true);
     4155        handled = true;
    41004156    }
    4101     else if (has_action("TOGGLEPIPSTATE", actions))
    4102     {
    4103         if (ctx && player.size() > 1)
    4104         {
    4105             needToMakePIPChange = (ctx->isPBP()) ? kPBPToPIP : kPIPToPBP;
    4106             if (pipChangeTimerId)
    4107                 KillTimer(pipChangeTimerId);
    4108             pipChangeTimerId = StartTimer(1, __LINE__);
    4109         }
    4110     }
    4111     else if (has_action("TOGGLEPIPWINDOW", actions))
    4112         ToggleActiveWindow(ctx, 1);
    4113     else
    4114         handled = false;
    41154157
    41164158    return handled;
    41174159}
     
    41314173            if (isDVD && ctx->buffer && ctx->buffer->DVD())
    41324174                ctx->buffer->DVD()->JumpToTitle(false);
    41334175
    4134             int clearpos = gContext->GetNumSetting("AltClearSavedPosition", 1);
    41354176            ctx->LockDeleteNVP(__FILE__, __LINE__);
    41364177            if (ctx->nvp)
    41374178            {
    4138                 if (clearpos && ctx->nvp->GetBookmark())
     4179                if (db_toggle_bookmark && ctx->nvp->GetBookmark())
    41394180                    ctx->nvp->ClearBookmark();
    41404181                else
    41414182                    ctx->nvp->SetBookmark();
     
    42004241void TV::ProcessNetworkControlCommand(PlayerContext *ctx,
    42014242                                      const QString &command)
    42024243{
     4244    bool ignoreKeys = ctx->IsNVPChangingBuffers();
    42034245#ifdef DEBUG_ACTIONS
    42044246    VERBOSE(VB_IMPORTANT, LOC + "ProcessNetworkControlCommand(" +
    4205             QString("%1)").arg(command));
     4247            QString("%1) ignoreKeys: %2").arg(command).arg(ignoreKeys));
    42064248#endif
    42074249
     4250    if (ignoreKeys)
     4251    {
     4252        VERBOSE(VB_IMPORTANT, LOC_WARN +
     4253                "Ignoring network control command"
     4254                "\n\t\t\tbecause ignoreKeys is set");
     4255        return;
     4256    }
     4257
    42084258    QStringList tokens = command.split(" ", QString::SkipEmptyParts);
    42094259    if (tokens.size() < 2)
    42104260    {
     
    43654415    {
    43664416        if (ctx->nvp)
    43674417            ctx->nvp->SetBookmark();
    4368         if (ctx->nvp && gContext->GetNumSetting("AutomaticSetWatched", 0))
     4418        if (ctx->nvp && db_auto_set_watched)
    43694419            ctx->nvp->SetWatched();
    43704420        SetExitPlayer(true, true);
    43714421    }
     
    45494599        swap(player[0],player[1]);
    45504600        player[0]->SetPIPState(kPIPOff);
    45514601        // End the old main context..
    4552         ForceNextStateNone(mctx);
     4602        ForceNextStateNone(mctx, __LINE__);
    45534603    }
    45544604
    45554605    VERBOSE(VB_PLAYBACK, LOC + "CreatePBP() -- end : "<<ok);
     
    45574607}
    45584608
    45594609/**
    4560  * \brief tear down remaining PBP video and restore
    4561  * fullscreen display
     4610 * \brief create PIP.
     4611 * \param info programinfo for PIP to create. is NULL for LiveTV PIP
    45624612 */
    4563 void TV::TeardownPBP(PlayerContext *ctx)
     4613bool TV::CreatePIP(PlayerContext *ctx, const ProgramInfo *info)
    45644614{
    45654615    PlayerContext *mctx = GetPlayer(ctx, 0);
     4616    if (!mctx)
     4617        return false;
    45664618
    4567     if (!mctx->nvp || !mctx->nvp->IsPlaying() ||
    4568         mctx->GetPIPState() < kPBPLeft || exitPlayerTimerId)
    4569     {
    4570         return;
    4571     }
     4619    VERBOSE(VB_PLAYBACK, LOC + "CreatePIP -- begin");
    45724620
    4573     VERBOSE(VB_PLAYBACK, LOC  + "TeardownPBP -- begin");
    4574 
    4575     long long mctx_frame = mctx->nvp->GetFramesPlayed();
    4576     mctx->PIPTeardown();
    4577     mctx->SetPIPState(kPIPOff);
    4578     mctx->buffer->Seek(0, SEEK_SET);
    4579     if (mctx->CreateNVP(this, myWindow, mctx->GetState(),
    4580                         embedWinID, &embedBounds))
     4621    if (mctx->isPBP())
    45814622    {
    4582         ScheduleStateChange(mctx);
    4583         mctx->StartOSD(this);
    4584         mctx->nvp->JumpToFrame(mctx_frame);
    4585 
    4586         //TODO find out where wantsToQuit is been enabled
    4587         wantsToQuit = false;
    4588 
    4589         SetSpeedChangeTimer(25, __LINE__);
     4623        VERBOSE(VB_IMPORTANT, LOC_ERR +
     4624                "CreatePIP called, but we're in PBP mode already, ignoring.");
     4625        return false;
    45904626    }
    4591     else
    4592         ForceNextStateNone(mctx);
    45934627
    4594     VERBOSE(VB_PLAYBACK, LOC + "TeardownPBP -- end");
    4595 }
     4628    bool has_vo = false, using_xvmc = false;
    45964629
    4597 /**
    4598  * \brief create PIP.
    4599  * \param info programinfo for PIP to create. is NULL for LiveTV PIP
    4600  */
    4601 bool TV::CreatePIP(PlayerContext *ctx, const ProgramInfo *info)
    4602 {
    4603     bool ret = false;
    4604     PlayerContext *mctx = GetPlayer(ctx, 0);
    4605 
    4606     VERBOSE(VB_PLAYBACK, LOC + "Starting CreatePIP -- begin");
    4607     bool using_xvmc = false;
    4608     QRect rect;
    4609     int pip_location;
    4610     if (mctx && mctx->nvp && mctx->nvp->getVideoOutput())
     4630    mctx->LockDeleteNVP(__FILE__, __LINE__);
     4631    if (mctx->nvp && mctx->nvp->getVideoOutput())
    46114632    {
    4612         pip_location = gContext->GetNumSetting("PIPLocation", 0);
    4613         rect = mctx->nvp->getVideoOutput()->GetPIPRect(pip_location, NULL);
     4633        has_vo = true;
    46144634        using_xvmc = mctx->nvp->getVideoOutput()->hasMCAcceleration();
    46154635    }
    4616     else
    4617     {
    4618         return ret;
    4619     }
     4636    mctx->UnlockDeleteNVP(__FILE__, __LINE__);
    46204637
     4638    if (!has_vo)
     4639        return false;
     4640
    46214641    /* TODO implement PIP solution for Xvmc playback */
    46224642    if (using_xvmc)
    46234643    {
    46244644        VERBOSE(VB_IMPORTANT, LOC + "PiP is not supported for XvMC");
    4625         return ret;
     4645        return false;
    46264646    }
    46274647
    46284648    PlayerContext *pipctx = new PlayerContext();
     
    46434663    else
    46444664    {
    46454665        delete pipctx;
    4646         return ret;
     4666        return false;
    46474667    }
    46484668
    46494669    // this is safe because we are already holding lock for ctx
    46504670    player.push_back(pipctx);
    46514671
    4652     ret = true;
    4653     return ret;
     4672    return true;
    46544673}
    46554674
    46564675int TV::find_player_index(const PlayerContext *ctx) const
     
    46624681}
    46634682
    46644683bool TV::StartPlayer(PlayerContext *mctx, PlayerContext *ctx,
    4665                      TVState desiredState, bool ispip)
     4684                     TVState desiredState)
    46664685{
    4667     if (ispip)
    4668         return StartPIPPlayer(mctx, ctx, desiredState);
     4686    bool wantPiP = ctx->isPIP();
    46694687
    4670     VERBOSE(VB_IMPORTANT, LOC + QString("StartPlayer(%1, %2, not pip) -- begin")
    4671             .arg(find_player_index(ctx)).arg(StateToString(desiredState)));
     4688    VERBOSE(VB_IMPORTANT, LOC + QString("StartPlayer(%1, %2, %3) -- begin")
     4689            .arg(find_player_index(ctx)).arg(StateToString(desiredState))
     4690            .arg((wantPiP) ? "PiP" : "main"));
    46724691
     4692    if (wantPiP)
     4693    {
     4694        if (mctx->nvp && ctx->StartPIPPlayer(this, desiredState) &&
     4695            ctx->nvp && PIPAddPlayer(mctx, ctx))
     4696        {
     4697            ScheduleStateChange(ctx);
     4698            VERBOSE(VB_IMPORTANT, "StartPlayer PiP -- end : ok");
     4699            return true;
     4700        }
     4701
     4702        ForceNextStateNone(ctx, __LINE__);
     4703        VERBOSE(VB_IMPORTANT, "StartPlayer PiP -- end : !ok");
     4704        return false;
     4705    }
     4706
    46734707    InitUDPNotifyEvent();
    46744708    bool ok = false;
    46754709    if (ctx->UseNullVideo())
     
    46774711        ok = ctx->CreateNVP(this, NULL, desiredState, 0, NULL);
    46784712        ScheduleStateChange(ctx);
    46794713        if (ok)
    4680             SetPIPPlayer(mctx, ctx);
     4714            ok = PIPAddPlayer(mctx, ctx);
    46814715    }
    46824716    else
    46834717    {
     
    46924726        SetSpeedChangeTimer(25, __LINE__);
    46934727    }
    46944728
    4695     VERBOSE(VB_IMPORTANT, LOC +
    4696             QString("StartPlayer(%1, %2, not pip) -- end %3")
     4729    VERBOSE(VB_IMPORTANT, LOC + QString("StartPlayer(%1, %2, %3) -- end %4")
    46974730            .arg(find_player_index(ctx)).arg(StateToString(desiredState))
    4698             .arg((ok) ? "ok" : "error"));
     4731            .arg((wantPiP) ? "PiP" : "main").arg((ok) ? "ok" : "error"));
    46994732
    47004733    return ok;
    47014734}
    47024735
    4703 bool TV::StartPIPPlayer(PlayerContext *mctx, PlayerContext *ctx,
    4704                         TVState desiredState)
     4736/// \brief Maps NVP of software scaled PIP to the NVP of the main player
     4737bool TV::PIPAddPlayer(PlayerContext *mctx, PlayerContext *pipctx)
    47054738{
    4706     if (mctx->nvp && ctx->StartPIPPlayer(this, desiredState) && ctx->nvp)
     4739    if (!mctx || !pipctx)
     4740        return false;
     4741
     4742    if (!mctx->nvp || !mctx->nvp->IsPlaying())
     4743        return false;
     4744
     4745    bool ok = false, addCondition = false;
     4746    if (pipctx->nvp)
    47074747    {
    4708         SetPIPPlayer(mctx, ctx);
    4709         ScheduleStateChange(ctx);
    4710         return true;
     4748        if (pipctx->nvp->UsingNullVideo())
     4749        {
     4750            addCondition = true;
     4751            PIPLocation loc = mctx->nvp->GetNextPIPLocation();
     4752            ok = mctx->nvp->AddPIPPlayer(pipctx->nvp, loc, 4000);
     4753        }
     4754        else if (pipctx->isPIP())
     4755        {
     4756            ok = ResizePIPWindow(pipctx);
     4757        }
    47114758    }
    4712     return false;
     4759
     4760    VERBOSE(VB_IMPORTANT,
     4761            QString("AddPIPPlayer null: %1 isPIP: %2 addCond: %3 ok: %4")
     4762            .arg(pipctx->nvp->UsingNullVideo())
     4763            .arg(pipctx->isPIP()).arg(addCondition).arg(ok));
     4764
     4765    return ok;
    47134766}
    47144767
    4715 /**
    4716  * \brief maps NVP of software scaled PIP  to the NVP of player
    4717  * context 0.
    4718  */
    4719 void TV::SetPIPPlayer(PlayerContext *mctx, PlayerContext *pipctx)
     4768/// \brief Unmaps NVP of software scaled PIP from the NVP of the main player
     4769bool TV::PIPRemovePlayer(PlayerContext *mctx, PlayerContext *pipctx)
    47204770{
    47214771    if (!mctx || !pipctx)
     4772        return false;
     4773
     4774    bool ok = false;
     4775    if (mctx->nvp && pipctx->nvp)
     4776        ok = mctx->nvp->RemovePIPPlayer(pipctx->nvp, 4000);
     4777
     4778    VERBOSE(VB_IMPORTANT, QString("PIPRemovePlayer ok: %1").arg(ok));
     4779
     4780    return ok;
     4781}
     4782
     4783/// \brief start/stop PIP/PBP
     4784void TV::PxPToggleView(PlayerContext *actx, bool wantPBP)
     4785{
     4786    if (player.size() <= 1)
     4787        PxPCreateView(actx, wantPBP);
     4788    else
     4789        PxPTeardownView(actx);
     4790}
     4791
     4792/// \brief start PIP/PBP
     4793void TV::PxPCreateView(PlayerContext *actx, bool wantPBP)
     4794{
     4795    if (!actx)
    47224796        return;
    47234797
    4724     bool setCondition = false;
    4725     if (mctx->nvp && mctx->nvp->IsPlaying())
     4798    QString err_msg = QString::null;
     4799    if ((player.size() > kMaxPBPCount) && (wantPBP || actx->isPBP()))
    47264800    {
    4727         if (pipctx->nvp)
    4728         {
    4729             if (pipctx->nvp->UsingNullVideo())
    4730                 setCondition = true;
    4731             else if (playerActive == 0 && pipctx->isPIP())
    4732                 ResizePIPWindow(pipctx);
    4733         }
    4734         else
    4735             setCondition = true;
     4801        err_msg = tr("Sorry, PBP only supports %1 video streams")
     4802            .arg(kMaxPBPCount);
     4803    }
    47364804
    4737         if (setCondition)
    4738         {
    4739             QMutex piplock;
    4740             piplock.lock();
    4741             mctx->nvp->SetPIPPlayer(pipctx->nvp);
    4742             pipPlayerSetCondition.wait(&piplock);
    4743             piplock.unlock();
    4744         }
     4805    if ((player.size() > kMaxPIPCount) &&
     4806        (!wantPBP || GetPlayer(actx,1)->isPIP()))
     4807    {
     4808        err_msg = tr("Sorry, PIP only supports %1 video streams")
     4809            .arg(kMaxPIPCount);
    47454810    }
     4811
     4812    if ((player.size() > 1) && (wantPBP ^ actx->isPBP()))
     4813        err_msg = tr("Sorry, can not mix PBP and PIP views");
     4814
     4815    if (!err_msg.isEmpty())
     4816    {
     4817        VERBOSE(VB_IMPORTANT, LOC_ERR + err_msg);
     4818        OSD *osd = GetOSDLock(actx);
     4819        if (osd)
     4820            osd->SetSettingsText(err_msg, 3);
     4821        ReturnOSDLock(actx, osd);
     4822        return;
     4823    }
     4824
     4825    bool ok = false;
     4826    if (wantPBP)
     4827        ok = CreatePBP(actx, NULL);
     4828    else
     4829        ok = CreatePIP(actx, NULL);
     4830    actx = GetPlayer(actx, -1); // CreatePBP/PIP mess with ctx's
     4831
     4832    QString msg = (ok) ?
     4833        ((wantPBP) ? tr("Creating PBP")      : tr("Creating PIP")) :
     4834        ((wantPBP) ? tr("Cannot create PBP") : tr("Cannot create PIP"));
     4835   
     4836    OSD *osd = GetOSDLock(actx);
     4837    if (osd)
     4838        osd->SetSettingsText(msg, 3);
     4839    ReturnOSDLock(actx, osd);
    47464840}
    47474841
    4748 /**
    4749  * \brief start/stop PIP/PBP
    4750  *
    4751  */
    4752 void TV::TogglePIPView(PlayerContext *lctx, bool ispbp)
     4842/// \brief stop PIP/PBP
     4843void TV::PxPTeardownView(PlayerContext *actx)
    47534844{
     4845    VERBOSE(VB_IMPORTANT, "PxPTeardownView()");
     4846
    47544847    QString msg;
     4848    PlayerContext *mctx = GetPlayer(actx, 0);
     4849    PlayerContext *dctx = NULL;
     4850    dctx = (mctx != actx)       ? actx               : dctx;
     4851    dctx = (2 == player.size()) ? GetPlayer(actx, 1) : dctx;
    47554852
    4756     if (player.size() > 1)
     4853    SetActive(actx, 0, false);
     4854
     4855    PlayerContext *ctx1 = GetPlayer(actx, 1);
     4856    msg = (ctx1->isPIP()) ? tr("Stopping PIP") : tr("Stopping PBP");
     4857    if (dctx)
    47574858    {
    4758         PlayerContext *ctx = player.back();
    4759         msg = "Stopping ";
    4760         msg += (ctx->isPIP()) ? "PIP" : "PBP";
    4761         if (playerActive != 0)
    4762             ToggleActiveWindow(lctx, 1);
    4763         ForceNextStateNone(ctx);
     4859        ForceNextStateNone(dctx, __LINE__);
    47644860    }
    47654861    else
    47664862    {
    4767         bool ok = false;
    4768         if (ispbp)
    4769             ok = CreatePBP(lctx, NULL);
    4770         else
    4771             ok = CreatePIP(lctx, NULL);
    4772         lctx = GetPlayer(lctx, -1); // CreatePBP/PIP mess with ctx's
    4773 
    4774         if (!ok)
     4863        if (player.size() > 2)
    47754864        {
    4776             msg = "Cannot Start ";
    4777             msg += (ispbp) ? "PBP" : "PIP";
     4865            msg = (ctx1->isPIP()) ?
     4866                tr("Stopping all PIPs") : tr("Stopping all PBPs");
    47784867        }
     4868
     4869        for (uint i = player.size() - 1; i > 0; i--)
     4870            ForceNextStateNone(GetPlayer(actx,i), __LINE__);
    47794871    }
    47804872
    4781     OSD *osd = GetOSDLock(lctx);
     4873    OSD *osd = GetOSDLock(mctx);
    47824874    if (osd)
    47834875        osd->SetSettingsText(msg, 3);
    4784     ReturnOSDLock(lctx, osd);
     4876    ReturnOSDLock(mctx, osd);
    47854877}
    47864878
    47874879/**
    47884880* \brief Change PIP View from PIP to PBP and visa versa
    47894881*/
    4790 void TV::TogglePIPState(PlayerContext *mctx, PIPState changeTo)
     4882void TV::PxPToggleType(PlayerContext *mctx, bool wantPBP)
    47914883{
    4792     QString before = (changeTo == kPIPToPBP) ? "PIP" : "PBP";
    4793     QString after  = (changeTo == kPIPToPBP) ? "PBP" : "PIP";
     4884    const QString before = (mctx->isPBP()) ? "PBP" : "PIP";
     4885    const QString after  = (wantPBP)       ? "PBP" : "PIP";
     4886
    47944887    VERBOSE(VB_PLAYBACK, LOC +
    4795             QString("TogglePIPState() converting from %1 to %2 -- begin")
    4796                     .arg(before).arg(after));
     4888            QString("PxPToggleType() converting from %1 to %2 -- begin")
     4889            .arg(before).arg(after));
    47974890
    4798     if (2 != player.size())
     4891    if (mctx->isPBP() == wantPBP)
    47994892    {
    4800         VERBOSE(VB_IMPORTANT, LOC_ERR +
    4801                 QString("TogglePIPState() -- end: # player contexts must be 2, "
    4802                         "but it is currently %1").arg(player.size()));
     4893        VERBOSE(VB_IMPORTANT, LOC_WARN +
     4894                "PxPToggleType() -- end: already in desired mode");
    48034895        return;
    48044896    }
    48054897
    4806     SetActive(mctx, 0);
     4898    uint max_cnt = min(kMaxPBPCount, kMaxPIPCount);
     4899    if (player.size() > max_cnt)
     4900    {
     4901        VERBOSE(VB_IMPORTANT, LOC_ERR +
     4902                QString("PxPToggleType() -- end: "
     4903                        "# player contexts must be %1 or less, "
     4904                        "but it is currently %1")
     4905                .arg(max_cnt).arg(player.size()));
    48074906
    4808     PlayerContext *pipctx = GetPlayer(mctx, 1);
     4907        QString err_msg = tr("Too many views to switch");
    48094908
    4810     if (!mctx->nvp || !pipctx->nvp || !pipctx->nvp->IsPlaying())
     4909        PlayerContext *actx = GetPlayer(mctx, -1);
     4910        OSD *osd = GetOSDLock(actx);
     4911        if (osd)
     4912            osd->SetSettingsText(err_msg, 3);
     4913        ReturnOSDLock(actx, osd);
    48114914        return;
     4915    }
    48124916
     4917    for (uint i = 0; i < player.size(); i++)
     4918    {
     4919        PlayerContext *ctx = GetPlayer(mctx, i);
     4920        ctx->LockDeleteNVP(__FILE__, __LINE__);
     4921        if (!ctx->nvp || !ctx->nvp->IsPlaying())
     4922        {
     4923            ctx->UnlockDeleteNVP(__FILE__, __LINE__);
     4924            VERBOSE(VB_IMPORTANT, LOC_ERR + "PxPToggleType() -- end: " +
     4925                    QString("nvp #%1 is not active, exiting without "
     4926                            "doing anything to avoid danger").arg(i));
     4927            return;
     4928        }
     4929        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
     4930    }
     4931
    48134932    MuteState mctx_mute = mctx->nvp->GetMuteState();
    48144933
    4815     vector<long long> pos;
    4816     pos.push_back(mctx->nvp->GetFramesPlayed());
    4817     pos.push_back(pipctx->nvp->GetFramesPlayed());
     4934    vector<long long> pos = TeardownAllNVPs(mctx);
    48184935
    4819     TeardownPIPWindows(mctx);
    4820 
    4821     if (changeTo == kPIPToPBP)
     4936    if (wantPBP)
    48224937    {
    4823         mctx->SetPIPState(kPBPLeft);
    4824         pipctx->SetPIPState(kPBPRight);
     4938        GetPlayer(mctx, 0)->SetPIPState(kPBPLeft);
     4939        GetPlayer(mctx, 1)->SetPIPState(kPBPRight);
    48254940    }
    48264941    else
    48274942    {
    4828         mctx->SetPIPState(kPIPOff);
    4829         pipctx->SetPIPState(kPIPonTV);
    4830         pipctx->SetNullVideo(true);
     4943        GetPlayer(mctx, 0)->SetPIPState(kPIPOff);
     4944        for (uint i = 1; i < player.size(); i++)
     4945        {
     4946            GetPlayer(mctx, i)->SetPIPState(kPIPonTV);
     4947            GetPlayer(mctx, i)->SetNullVideo(true);
     4948        }
    48314949    }
    48324950
    4833     RestartPIPWindows(mctx, pos, mctx_mute);
     4951    RestartAllNVPs(mctx, pos, mctx_mute);
    48344952
    48354953    VERBOSE(VB_PLAYBACK, LOC +
    4836             QString("TogglePIPState() converting from %1 to %2 -- end")
     4954            QString("PxPToggleType() converting from %1 to %2 -- end")
    48374955            .arg(before).arg(after));
    48384956}
    48394957
    4840 void TV::ToggleActiveWindow(PlayerContext *lctx, int ctx_index)
     4958/**
     4959 * \brief resize PIP Window. done when changing channels or swapping PIP
     4960 */
     4961bool TV::ResizePIPWindow(PlayerContext *ctx)
    48414962{
    4842     if (player.size() == 1 || ctx_index < 1)
    4843         return;
    4844 
    4845     ClearOSD(lctx);
    4846 
    4847     PlayerContext *ctx = GetPlayer(lctx, ctx_index);
    4848     if (ctx->nvp)
     4963    VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- begin");
     4964    PlayerContext *mctx = GetPlayer(ctx, 0);
     4965    if (mctx->nvp && ctx->nvp)
    48494966    {
    4850         int new_index = 0;
    4851         lockTimerOn = false;
     4967        QRect rect;
    48524968
    4853         if (playerActive != ctx_index)
    4854             new_index = ctx_index;
     4969        mctx->LockDeleteNVP(__FILE__, __LINE__);
     4970        if (mctx->nvp)
     4971        {
     4972            PIPLocation loc = mctx->nvp->GetNextPIPLocation();
     4973            VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- loc "<<loc);
     4974            if (loc != kPIP_END)
     4975            {
     4976                rect = mctx->nvp->getVideoOutput()->GetPIPRect(
     4977                    loc, ctx->nvp, false);
     4978            }
     4979        }
     4980        mctx->UnlockDeleteNVP(__FILE__, __LINE__);
    48554981
    4856         PlayerContext *mctx = GetPlayer(lctx, 0);
    4857         if (mctx->nvp &&
    4858             mctx->nvp->getVideoOutput() &&
    4859             !ctx->isPBP())
     4982        if (rect.isValid())
    48604983        {
    4861             mctx->nvp->getVideoOutput()->PadPIPImage(new_index);
     4984            ctx->ResizePIPWindow(rect);
     4985            VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- end : ok");
     4986            return true;
    48624987        }
    4863 
    4864         SetActive(lctx, new_index);
    48654988    }
    4866 
    4867     PlayerContext *actx = GetPlayer(lctx, -1);
    4868     OSD *osd = GetOSDLock(actx);
    4869     if (osd)
    4870         osd->SetSettingsText(tr("Changed Active Window"), 3);
    4871     ReturnOSDLock(actx, osd);
     4989    VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- end : !ok");
     4990    return false;
    48724991}
    48734992
    4874 /**
    4875  * \brief wake TV thread when pip player var is set in the main NVP
    4876  */
    4877 void TV::WakeSetPIPPlayerCond(void)
    4878 {
    4879     pipPlayerSetCondition.wakeAll();
    4880 }
    4881 
    4882 /**
    4883  * \brief resize PIP Window. done when changing channels or swapping PIP
    4884  */
    4885 void TV::ResizePIPWindow(PlayerContext *ctx)
    4886 {
    4887     PlayerContext *actx = GetPlayer(ctx, -1);
    4888     int loc = gContext->GetNumSetting("PIPLocation", 0);
    4889     if (actx->nvp && ctx->nvp)
    4890     {
    4891         QRect rect =
    4892             actx->nvp->getVideoOutput()->GetPIPRect(loc, ctx->nvp, false);
    4893         ctx->ResizePIPWindow(rect);
    4894     }
    4895 }
    4896 
    48974993bool TV::IsPIPSupported(const PlayerContext *ctx) const
    48984994{
    48994995    const PlayerContext *mctx = NULL;
     
    49105006    return yes;
    49115007}
    49125008
    4913 /**
    4914 * \brief Teardown all NVP's in preparation for PIP Swap or change from PIP <-> PBP
    4915 */
    4916 void TV::TeardownPIPWindows(PlayerContext *lctx)
     5009/** \brief Teardown all NVP's in preparation for PxP Swap or
     5010 *         change from PIP -> PBP or PBP -> PIP
     5011 */
     5012vector<long long> TV::TeardownAllNVPs(PlayerContext *lctx)
    49175013{
    4918     SetActive(lctx, 0);
     5014    vector<long long> pos;
     5015    for (uint i = 0; i < player.size(); i++)
     5016    {
     5017        const PlayerContext *ctx = GetPlayer(lctx, i);
     5018        ctx->LockDeleteNVP(__FILE__, __LINE__);
     5019        pos.push_back((ctx->nvp) ? ctx->nvp->GetFramesPlayed() : 0);
     5020        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
     5021    }
    49195022
    49205023    for (uint i = 0; i < player.size(); i++)
    49215024    {
    49225025        PlayerContext *ctx = GetPlayer(lctx, i);
    49235026        ctx->PIPTeardown();
    49245027    }
     5028
     5029    return pos;
    49255030}
    49265031
    49275032/**
     5033 * \brief tear down remaining PBP video and restore
     5034 * fullscreen display
     5035 */
     5036void TV::PBPRestartMainNVP(PlayerContext *mctx)
     5037{
     5038    VERBOSE(VB_PLAYBACK, LOC  + "PBPRestartMainNVP -- begin");
     5039
     5040    mctx->LockDeleteNVP(__FILE__, __LINE__);
     5041    if (!mctx->nvp || !mctx->nvp->IsPlaying() ||
     5042        mctx->GetPIPState() != kPBPLeft || exitPlayerTimerId)
     5043    {
     5044        mctx->UnlockDeleteNVP(__FILE__, __LINE__);
     5045        VERBOSE(VB_PLAYBACK, LOC  + "PBPRestartMainNVP -- end !ok !valid");
     5046        return;
     5047    }
     5048
     5049    long long mctx_frame = mctx->nvp->GetFramesPlayed();
     5050    mctx->UnlockDeleteNVP(__FILE__, __LINE__);
     5051
     5052    mctx->PIPTeardown();
     5053    mctx->SetPIPState(kPIPOff);
     5054    mctx->buffer->Seek(0, SEEK_SET);
     5055
     5056    if (mctx->CreateNVP(this, myWindow, mctx->GetState(),
     5057                        embedWinID, &embedBounds))
     5058    {
     5059        ScheduleStateChange(mctx);
     5060        mctx->StartOSD(this);
     5061        mctx->nvp->JumpToFrame(mctx_frame);
     5062        SetSpeedChangeTimer(25, __LINE__);
     5063        VERBOSE(VB_PLAYBACK, LOC + "PBPRestartMainNVP -- end ok");
     5064        return;
     5065    }
     5066
     5067    ForceNextStateNone(mctx, __LINE__);
     5068    VERBOSE(VB_PLAYBACK, LOC +
     5069            "PBPRestartMainNVP -- end !ok NVP did not restart");
     5070}
     5071
     5072/**
    49285073* \brief Recreate Main and PIP windows. Could be either PIP or PBP views.
    49295074*/
    4930 void TV::RestartPIPWindows(PlayerContext *lctx,
    4931                            const vector<long long> &pos,
    4932                            MuteState mctx_mute)
     5075void TV::RestartAllNVPs(PlayerContext *lctx,
     5076                        const vector<long long> &pos,
     5077                        MuteState mctx_mute)
    49335078{
    4934     QString loc = LOC + QString("RestartPIPWindows()");
     5079    QString loc = LOC + QString("RestartAllNVPs(): ");
    49355080
    49365081    PlayerContext *mctx = GetPlayer(lctx, 0);
    49375082
     
    49435088    if (StateIsLiveTV(mctx->GetState()))
    49445089        mctx->buffer->Unpause();
    49455090
    4946     bool ok = StartPlayer(mctx, mctx, mctx->GetState(), false);
     5091    bool ok = StartPlayer(mctx, mctx, mctx->GetState());
    49475092
    49485093    if (ok)
    49495094    {
     
    49535098    {
    49545099        VERBOSE(VB_IMPORTANT, loc +
    49555100                "Failed to restart new main context (was pip context)");
    4956         ForceNextStateNone(mctx);
     5101        ForceNextStateNone(mctx, __LINE__);
    49575102        return;
    49585103    }
    49595104
     
    49665111        if (StateIsLiveTV(pipctx->GetState()))
    49675112            pipctx->buffer->Unpause();
    49685113
    4969         ok = StartPlayer(mctx, pipctx, pipctx->GetState(), pipctx->isPIP());
     5114        ok = StartPlayer(mctx, pipctx, pipctx->GetState());
    49705115
    49715116        if (ok)
    49725117        {
     
    49785123        { // TODO print OSD informing user of Swap failure ?
    49795124            VERBOSE(VB_IMPORTANT, loc +
    49805125                    "Failed to restart new pip context (was main context)");
    4981             ForceNextStateNone(pipctx);
     5126            ForceNextStateNone(pipctx, __LINE__);
    49825127        }
    49835128    }
    49845129
     
    49885133        mctx->nvp->SetMuteState(mctx_mute);
    49895134}
    49905135
    4991 void TV::SwapPIP(PlayerContext *lctx, int ctx_index, bool ispbp)
     5136void TV::PxPSwap(PlayerContext *mctx, int ctx_index)
    49925137{
    49935138    lockTimerOn = false;
    49945139
    4995     PlayerContext *mctx = GetPlayer(lctx, 0);
    4996     if (player.size() == 1)
     5140    if (player.size() <= 1 || !mctx)
    49975141        return;
    49985142
    4999     PlayerContext *pipctx = GetPlayer(lctx, ctx_index);
     5143    PlayerContext *pipctx = GetPlayer(mctx, ctx_index);
     5144    ctx_index = find_player_index(pipctx);
     5145    if (ctx_index < 0 || !pipctx)
     5146        return;
    50005147
    50015148    if (!mctx->nvp || !pipctx->nvp || !pipctx->nvp->IsPlaying())
    50025149        return;
     
    50045151    VERBOSE(VB_PLAYBACK, LOC + "SwapPIP -- begin");
    50055152
    50065153    MuteState mctx_mute = mctx->nvp->GetMuteState();
    5007 
    5008     vector<long long> pos;
    5009     for (uint i = 0; i < player.size(); i++)
    5010     {
    5011         const PlayerContext *ctx = GetPlayer(lctx, i);
    5012         ctx->LockDeleteNVP(__FILE__, __LINE__);
    5013         pos.push_back((ctx->nvp) ? ctx->nvp->GetFramesPlayed() : 0);
    5014         ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    5015     }
    5016 
    50175154    bool useNullVideo = pipctx->UseNullVideo();
    50185155
    5019     TeardownPIPWindows(lctx);
     5156    vector<long long> pos = TeardownAllNVPs(mctx);
    50205157
    5021     swap(player[0], player[ctx_index]);
    5022     swap(pos[0],    pos[ctx_index]);
    5023 
    5024     pipctx->SetPIPState((ispbp) ? kPBPLeft: kPIPOff);
    5025 
     5158    swap(player[0],           player[ctx_index]);
     5159    swap(pos[0],              pos[ctx_index]);
     5160    swap(player[0]->pipState, player[ctx_index]->pipState);
     5161    playerActive = (ctx_index == playerActive) ?
     5162        0 : ((ctx_index == 0) ? ctx_index : playerActive);
     5163   
    50265164    if (useNullVideo)
    50275165        mctx->SetNullVideo(true);
    50285166
    5029     mctx->SetPIPState((ispbp) ? kPBPRight: kPIPonTV);
    5030 
    5031     RestartPIPWindows(mctx, pos, mctx_mute);
     5167    RestartAllNVPs(mctx, pos, mctx_mute);
    50325168}
    50335169
    50345170void TV::DoPlay(PlayerContext *ctx)
     
    53875523            ctx->playingInfo->ApplyTranscoderProfileChange(profile);
    53885524            QString jobHost = "";
    53895525
    5390             if (gContext->GetNumSetting("JobsRunOnRecordHost", 0))
     5526            if (db_run_jobs_on_remote)
    53915527                jobHost = ctx->playingInfo->hostname;
    53925528
    53935529            OSD *osd = GetOSDLock(ctx);
     
    55985734
    55995735    if (testrec && testrec->IsValidRecorder())
    56005736    {
    5601         // pause the decoder first, so we're not reading to close to the end.
     5737        PlayerContext *mctx = GetPlayer(ctx, 0);
     5738        if (mctx != ctx)
     5739            PIPRemovePlayer(mctx, ctx);
    56025740
     5741        // pause the decoder first, so we're not reading too close to the end.
    56035742        ctx->buffer->IgnoreLiveEOF(true);
    56045743        ctx->buffer->StopReads();
    56055744        ctx->nvp->PauseDecoder();
     
    56095748        ctx->buffer->WaitForPause();
    56105749        ctx->nvp->StopPlaying();
    56115750        ctx->recorder->StopLiveTV();
    5612         {
    5613             ctx->SetNVP(NULL);
    5614             PlayerContext *mctx = GetPlayer(ctx, 0);
    5615             if (ctx != mctx)
    5616                 SetPIPPlayer(mctx, ctx);
    5617         }
     5751        ctx->SetNVP(NULL);
    56185752
    56195753        // now restart stuff
    56205754        ctx->lastSignalUIInfo.clear();
     
    56585792                ok = true;
    56595793                ctx->StartOSD(this);
    56605794                ctx->PushPreviousChannel();
    5661                 if (ctx && (player.size() > 1))
    5662                 {
    5663                     if (0 == playerActive)
    5664                     {
    5665                         PlayerContext *ctx1 = GetPlayer(ctx, 1);
    5666                         SetPIPPlayer(mctx, ctx1);
    5667                     }
    5668                     else
    5669                     {
    5670                         PlayerContext *mctx = GetPlayer(ctx, 0);
    5671                         SetPIPPlayer(mctx, ctx);
    5672                     }
    5673                 }
     5795                for (uint i = 1; i < player.size(); i++)
     5796                    PIPAddPlayer(mctx, GetPlayer(ctx, i));
    56745797
    56755798                SetSpeedChangeTimer(25, __LINE__);
    56765799            }
     
    69577080    margin = margin * 5;
    69587081    QDomElement xmldata;
    69597082    XMLParse *theme = new XMLParse();
    6960     if (!allowembed ||
    6961         !theme->LoadTheme(xmldata, str) ||
    6962         !gContext->GetNumSetting("ContinueEmbeddedTVPlay", 0) ||
    6963         ctx->nvp->IsNearEnd(margin) ||
    6964         ctx->paused)
     7083    if (!allowembed || !theme->LoadTheme(xmldata, str) ||
     7084        !db_continue_embedded || ctx->nvp->IsNearEnd(margin) || ctx->paused)
    69657085    {
    69667086        if (!stayPaused)
    69677087            DoPause(ctx, false);
     
    69767096
    69777097void TV::DoEditSchedule(int editType)
    69787098{
    6979     PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    6980     mctx->LockPlayingInfo(__FILE__, __LINE__);
    6981     if (!mctx->playingInfo)
     7099    PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     7100
     7101    actx->LockPlayingInfo(__FILE__, __LINE__);
     7102    if (!actx->playingInfo)
    69827103    {
    69837104        VERBOSE(VB_IMPORTANT,
    6984                 LOC_ERR + "doEditSchedule(): no active mctx->playingInfo.");
    6985         mctx->UnlockPlayingInfo(__FILE__, __LINE__);
    6986         ReturnPlayerLock(mctx);
     7105                LOC_ERR + "doEditSchedule(): no active ctx playingInfo.");
     7106        actx->UnlockPlayingInfo(__FILE__, __LINE__);
     7107        ReturnPlayerLock(actx);
    69877108        return;
    69887109    }
    69897110
    69907111    // Collect channel info
    6991     uint    chanid  = mctx->playingInfo->chanid.toUInt();
    6992     QString channum = mctx->playingInfo->chanstr;
    6993     mctx->UnlockPlayingInfo(__FILE__, __LINE__);
     7112    uint    chanid  = actx->playingInfo->chanid.toUInt();
     7113    QString channum = actx->playingInfo->chanstr; channum.detach();
     7114    actx->UnlockPlayingInfo(__FILE__, __LINE__);
    69947115
    6995     ClearOSD(mctx);
     7116    ClearOSD(actx);
    69967117
    69977118    // Resize window to the MythTV GUI size
    6998 
     7119    PlayerContext *mctx = GetPlayer(actx, 0);
    69997120    if (mctx->nvp && mctx->nvp->getVideoOutput())
    70007121        mctx->nvp->getVideoOutput()->ResizeForGui();
    70017122    MythMainWindow *mwnd = gContext->GetMainWindow();
    7002     bool using_gui_size_for_tv = gContext->GetNumSetting("GuiSizeForTV", 0);
    7003     if (!using_gui_size_for_tv)
     7123
     7124    if (!db_use_gui_size_for_tv)
    70047125    {
    70057126        mwnd->setGeometry(saved_gui_bounds.left(), saved_gui_bounds.top(),
    70067127                          saved_gui_bounds.width(), saved_gui_bounds.height());
     
    70267147                player = this;
    70277148            if (StateIsLiveTV(GetState(mctx)))
    70287149            {
    7029                 ReturnPlayerLock(mctx);
     7150                ReturnPlayerLock(actx);
    70307151                changeChannel = GuideGrid::Run(chanid, channum, false,
    70317152                                               player, allowsecondary);
    7032                 mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     7153                actx = GetPlayerReadLock(0, __FILE__, __LINE__);
    70337154            }
    70347155            else
    70357156            {
    7036                 ReturnPlayerLock(mctx);
     7157                ReturnPlayerLock(actx);
    70377158                GuideGrid::Run(chanid, channum, false, player);
    7038                 mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     7159                actx = GetPlayerReadLock(0, __FILE__, __LINE__);
    70397160            }
    70407161            break;
    70417162        }
    70427163        case kScheduleProgramFinder:
    70437164            if (!mctx->paused)
    70447165                DoPause(mctx, false);
     7166            ReturnPlayerLock(actx);
    70457167            RunProgramFind(false, false);
     7168            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
    70467169            break;
    70477170        case kScheduledRecording:
    70487171        {
    70497172            if (mctx->paused)
    70507173                DoPause(mctx, false);
     7174
    70517175            mctx->LockPlayingInfo(__FILE__, __LINE__);
     7176            const ProgramInfo pginfo(*mctx->playingInfo);
     7177            mctx->UnlockPlayingInfo(__FILE__, __LINE__);
     7178            ReturnPlayerLock(actx);
     7179
    70527180            ScheduledRecording *record = new ScheduledRecording();
    7053             record->loadByProgram(mctx->playingInfo);
     7181            record->loadByProgram(&pginfo);
    70547182            record->exec();
    70557183            record->deleteLater();
    7056             mctx->UnlockPlayingInfo(__FILE__, __LINE__);
     7184
     7185            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
    70577186            break;
    70587187        }
    70597188        case kViewSchedule:
    70607189        {
    70617190            showvideo = VideoThemeCheck(mctx, "conflict-video", stayPaused);
     7191            ReturnPlayerLock(actx);
    70627192            RunViewScheduledPtr((void *)this, showvideo);
     7193            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
    70637194            break;
    70647195        }
    70657196        case kPlaybackBox:
    70667197        {
    70677198            showvideo = VideoThemeCheck(mctx, "playback-video", stayPaused);
     7199            ReturnPlayerLock(actx);
    70687200            nextProgram = RunPlaybackBoxPtr((void *)this, showvideo);
     7201            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
    70697202        }
    70707203    }
    70717204
     
    70807213        embedCheckTimerId = 0;
    70817214    }
    70827215
    7083     if (StateIsPlaying(GetState(mctx)) &&
     7216    VERBOSE(VB_PLAYBACK, LOC
     7217            <<"state: "<<StateToString(GetState(mctx))
     7218            <<"!stayPaused: "<<stayPaused<<" mctx->paused: "<<mctx->paused);
     7219    if ((StateIsPlaying(GetState(mctx)) || StateIsLiveTV(GetState(mctx))) &&
    70847220        !stayPaused && mctx->paused)
    70857221    {
     7222        VERBOSE(VB_PLAYBACK, LOC + "Unpausing video");
     7223        // this should unpause video..
    70867224        DoPause(mctx, true);
    70877225    }
    7088     ReturnPlayerLock(mctx);
     7226    ReturnPlayerLock(actx);
    70897227
    70907228    mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
    70917229    if (nextProgram)
    70927230    {
    7093         if (nextProgPIPState == kPIPonTV)
     7231        if (jumpToProgramPIPState == kPIPonTV)
    70947232            CreatePIP(mctx, nextProgram);
    7095         else if (nextProgPIPState == kPBPLeft)
     7233        else if (jumpToProgramPIPState == kPBPLeft)
    70967234            CreatePBP(mctx, nextProgram);
    70977235        else
    70987236        {
    7099             setLastProgram(nextProgram);
     7237            SetLastProgram(nextProgram);
    71007238            jumpToProgram = true;
    71017239            SetExitPlayer(true, true);
    71027240        }
    71037241        mctx = GetPlayer(mctx, 0); // CreatePBP/PIP mess with ctx's
    71047242
    7105         nextProgPIPState = kPIPOff;
     7243        jumpToProgramPIPState = kPIPOff;
    71067244        delete nextProgram;
    71077245        nextProgram = NULL;
    71087246    }
     
    71107248
    71117249    mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    71127250    // Resize the window back to the MythTV Player size
    7113     if (!using_gui_size_for_tv)
     7251    if (!db_use_gui_size_for_tv)
    71147252    {
    71157253        mwnd->setGeometry(player_bounds.left(), player_bounds.top(),
    71167254                          player_bounds.width(), player_bounds.height());
     
    71327270
    71337271void TV::EditSchedule(const PlayerContext *ctx, int editType)
    71347272{
    7135     if (ctx && (player.size() > 1))
    7136         return;
    7137 
    71387273    // post the request to the main UI thread
    71397274    // it will be caught in eventFilter and processed as CustomEvent
    71407275    // this will create the program guide window (widget)
     
    74947629                {
    74957630                    ctx->nvp->SetWatchingRecording(false);
    74967631                    ctx->nvp->SetLength(filelen);
    7497                     ctx->ChangeState(kState_WatchingPreRecorded);
     7632                    ctx->ChangeState(kState_WatchingPreRecorded, __LINE__);
    74987633                    ScheduleStateChange(ctx);
    74997634                }
    75007635            }
     
    76447779
    76457780    if (message.left(12) == "EXIT_TO_MENU")
    76467781    {
    7647         int exitprompt = gContext->GetNumSetting("PlaybackExitPrompt");
    7648 
    76497782        PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    76507783        for (uint i = 0; mctx && (i < player.size()); i++)
    76517784        {
    76527785            PlayerContext *ctx = GetPlayer(mctx, i);
    76537786            if (!ctx->nvp)
    76547787                continue;
    7655             if (exitprompt == 1 || exitprompt == 2)
     7788            if (db_playback_exit_prompt == 1 || db_playback_exit_prompt == 2)
    76567789                ctx->nvp->SetBookmark();
    7657             if (ctx->nvp && gContext->GetNumSetting("AutomaticSetWatched", 0))
     7790            if (ctx->nvp && db_auto_set_watched)
    76587791                ctx->nvp->SetWatched();
    76597792        }
    76607793
     
    77337866        }
    77347867    }
    77357868
    7736     int player_cnt = 0;
     7869    if (message.left(9) == "START_EPG")
    77377870    {
    7738         PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
    7739         player_cnt = player.size();
    7740         ReturnPlayerLock(mctx);
    7741     }
    7742 
    7743     if (message.left(9) == "START_EPG" && (1 == player_cnt))
    7744     {
    77457871        int editType = tokens[1].toInt();
    77467872        DoEditSchedule(editType);
    77477873    }
     
    78447970        browsechannum   = ctx->playingInfo->chanstr;
    78457971        browsechanid    = ctx->playingInfo->chanid;
    78467972        browsestarttime = ctx->playingInfo->startts.toString();
     7973        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    78477974
    78487975        BrowseDispInfo(ctx, BROWSE_SAME);
    78497976
     
    78527979            KillTimer(browseTimerId);
    78537980        browseTimerId = StartTimer(kBrowseTimeout, __LINE__);
    78547981    }
    7855     ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     7982    else
     7983    {
     7984        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     7985    }
    78567986}
    78577987
    78587988/** \fn TV::BrowseEnd(PlayerContext*, bool)
     
    79868116    QString cmdmsg("");
    79878117    if (ctx->playingInfo->GetAutoExpireFromRecorded() == kLiveTVAutoExpire)
    79888118    {
    7989         int autoexpiredef = gContext->GetNumSetting("AutoExpireDefault", 0);
    7990         ctx->playingInfo->SetAutoExpire(autoexpiredef);
     8119        ctx->playingInfo->SetAutoExpire(db_autoexpire_default);
    79918120        ctx->playingInfo->ApplyRecordRecGroupChange("Default");
    79928121        cmdmsg = tr("Record");
    79938122        ctx->SetPseudoLiveTV(ctx->playingInfo, kPseudoRecording);
     
    81558284    SetUpdateOSDPosition(false);
    81568285}
    81578286
    8158 void TV::SetActive(PlayerContext *ctx, int index)
     8287#include <cassert>
     8288void TV::SetActive(PlayerContext *lctx, int index, bool osd_msg)
    81598289{
    8160     VERBOSE(VB_PLAYBACK, "TV::SetActive -- begin");
     8290    assert(lctx);
     8291    if (!lctx)
     8292        return;
    81618293
     8294    QString loc = LOC + QString("SetActive(%1,%2) was %3")
     8295        .arg(index).arg((osd_msg) ? "with OSD" : "w/o OSD").arg(playerActive);
     8296
     8297    VERBOSE(VB_PLAYBACK, loc + " -- begin");
     8298
    81628299    if (playerActive == index)
    81638300    {
    8164         VERBOSE(VB_PLAYBACK, "TV::SetActive -- index == active context");
     8301        VERBOSE(VB_PLAYBACK, loc + " -- end (index == playerActive)");
    81658302        return;
    81668303    }
    81678304
    8168     VERBOSE(VB_PLAYBACK, "TV::SetActive -- lock");
     8305    index = (index < 0) ? (playerActive+1) % player.size() : index;
     8306    index = (index >= (int)player.size()) ? 0 : index;
    81698307
    8170     PlayerContext *actx = NULL;
     8308    playerActive = index;
    81718309
    8172     if (playerActive > -1 && !ctx)
     8310    for (int i = 0; i < (int)player.size(); i++)
    81738311    {
    8174         actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    8175         ReturnPlayerLock(actx);
     8312        PlayerContext *ctx = GetPlayer(lctx, i);
     8313        ctx->LockDeleteNVP(__FILE__, __LINE__);
     8314        if (ctx->nvp)
     8315            ctx->nvp->SetPIPActive(i == playerActive);
     8316        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
    81768317    }
    81778318
    8178     VERBOSE(VB_PLAYBACK,
    8179             QString("TV::SetActive changing playerActive "
    8180                     "from %1 to %2")
    8181                     .arg(playerActive).arg(index));
    8182 
    8183     playerActive = index;
    8184 
    8185     if (!ctx)
     8319#if 0
     8320    // seems reduntant, except maybe for main player? -dtk
     8321    if (osd_msg)
    81868322    {
    8187         actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    8188         ReturnPlayerLock(actx);
     8323        PlayerContext *actx = GetPlayer(lctx, -1);
     8324        OSD *osd = GetOSDLock(actx);
     8325        if (osd)
     8326            osd->SetSettingsText(tr("Active").arg(playerActive), 3);
     8327        ReturnOSDLock(actx, osd);
    81898328    }
     8329#endif
     8330
     8331    VERBOSE(VB_PLAYBACK, loc + " -- end");
    81908332}
    81918333
    81928334void TV::TreeMenuEntered(OSDListTreeType *tree, OSDGenericTree *item)
     
    87338875        EditSchedule(actx, kScheduleProgramFinder);
    87348876    else if (action == "SCHEDULE")
    87358877        EditSchedule(actx, kScheduledRecording);
    8736     else if ((action == "JUMPPREV") ||
    8737              ((action == "PREVCHAN") && (!StateIsLiveTV(GetState(actx)))))
    8738     {
    8739         if (PromptRecGroupPassword(actx))
    8740         {
    8741             actx->nvp->SetBookmark();
    8742             jumpToProgram = true;
    8743             SetExitPlayer(true, true);
    8744         }
    8745     }
    87468878    else if (action == "VIEWSCHEDULED")
    87478879        EditSchedule(actx, kViewSchedule);
    8748     else if (action == "JUMPREC")
     8880    else if (HandleJumpToProgramAction(actx, QStringList(action)))
    87498881    {
    8750         if (gContext->GetNumSetting("JumpToProgramOSD", 1) &&
    8751             StateIsPlaying(actx->GetState()))
    8752         {
    8753             if (jumpMenuTimerId)
    8754                 KillTimer(jumpMenuTimerId);
    8755             jumpMenuTimerId = StartTimer(1, __LINE__);
    8756         }
    8757         else if (RunPlaybackBoxPtr)
    8758             EditSchedule(actx, kPlaybackBox);
    87598882    }
    8760     else if (action == "TOGGLEPIPMODE")
     8883    else if (PxPHandleAction(actx, QStringList(action)))
    87618884    {
    8762         ReturnPlayerLock(actx);
     8885        // Hide the tree on this old active context..
     8886        tree->SetVisible(false);
     8887        tree->disconnect();
     8888        OSD *osd = GetOSDLock(actx);
     8889        if (osd)
     8890            osd->HideTreeMenu();
     8891        ReturnOSDLock(actx, osd);
     8892        ClearOSD(actx);
    87638893
    8764         actx = GetPlayerWriteLock(-1, __FILE__, __LINE__);
    8765         TogglePIPView(actx);
    8766         ReturnPlayerLock(actx);
     8894        hidetree = true;
    87678895
    8768         actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     8896        actx = GetPlayer(actx,-1); // "NEXTPIPWINDOW" changes active context..
    87698897    }
    8770     else if (action == "TOGGLEPBPMODE")
    8771     {
    8772         needToMakePIPChange = kPBPToggle;
    8773         if (pipChangeTimerId)
    8774             KillTimer(pipChangeTimerId);
    8775         pipChangeTimerId = StartTimer(1, __LINE__);
    8776     }
    8777     else if (action == "TOGGLEPIPWINDOW")
    8778         ToggleActiveWindow(actx, 1);
    8779     else if (action == "TOGGLEPIPSTATE")
    8780     {
    8781         needToMakePIPChange = (actx->isPBP()) ? kPBPToPIP : kPIPToPBP;
    8782         if (pipChangeTimerId)
    8783             KillTimer(pipChangeTimerId);
    8784         pipChangeTimerId = StartTimer(1, __LINE__);
    8785     }
    8786     else if (action == "SWAPPIP")
    8787     {
    8788         needToMakePIPChange = (actx->isPBP()) ? kPBPSwap : kPIPSwap;
    8789         if (pipChangeTimerId)
    8790             KillTimer(pipChangeTimerId);
    8791         pipChangeTimerId = StartTimer(1, __LINE__);
    8792     }
    87938898    else if (StateIsLiveTV(GetState(actx)))
    87948899    {
    87958900        if (action == "TOGGLEBROWSE")
     
    88338938            DoQueueTranscode(actx, "Medium Quality");
    88348939        else if (action == "QUEUETRANSCODE_LOW")
    88358940            DoQueueTranscode(actx, "Low Quality");
    8836         else if (action.left(8) == "JUMPPROG")
    8837         {
    8838             SetJumpToProgram(action.section(" ",1,-2),
    8839                              action.section(" ",-1,-1).toInt());
    8840             actx->nvp->SetBookmark();
    8841             jumpToProgram = true;
    8842             SetExitPlayer(true, true);
    8843         }
    88448941        else
    88458942        {
    88468943            VERBOSE(VB_IMPORTANT, LOC_ERR +
     
    89018998        delete treeMenu;
    89028999
    89039000    treeMenu = new OSDGenericTree(NULL, "treeMenu");
    8904     OSDGenericTree *item, *subitem;
    89059001
    89069002    bool freeRecorders = RemoteGetFreeRecorderCount();
    89079003
    8908     if (IsPIPSupported(ctx) && ((ctx && (player.size() > 1)) || freeRecorders))
    8909     {
    8910         // Picture-in-Picture
    8911         item = new OSDGenericTree(treeMenu, tr("Picture-in-Picture"));
    8912         if (ctx && (player.size() == 1))
    8913         {
    8914             subitem = new OSDGenericTree(item, tr("Enable PIP"),
    8915                                          "TOGGLEPIPMODE");
    8916             subitem = new OSDGenericTree(item, tr("Enable PBP"),
    8917                                          "TOGGLEPBPMODE");
    8918         }
    8919         else
    8920         {
    8921             QString option = "Disable ";
    8922             QString switchTo = "Switch to ";
    8923             QString pipType = (ctx->isPBP()) ? "PBP" : "PIP";
    8924             QString changeTo = (ctx->isPBP()) ? "PIP" : "PBP";
    8925             option += pipType;
    8926             switchTo += changeTo;
    8927             QString toggleMode = QString("TOGGLE%1MODE").arg(pipType);
    8928             subitem = new OSDGenericTree(item, option, toggleMode);
    8929             subitem = new OSDGenericTree(item, tr("Swap Windows"),
    8930                                          "SWAPPIP");
    8931             subitem = new OSDGenericTree(item, tr("Change Active Window"),
    8932                                          "TOGGLEPIPWINDOW");
    8933             subitem = new OSDGenericTree(item, switchTo, "TOGGLEPIPSTATE");
    8934         }
    8935     }
    8936 
    89379004    if (freeRecorders && ctx->recorder)
    89389005    {
    89399006        // Input switching
     
    90119078        }
    90129079    }
    90139080
     9081    FillMenuPxP(ctx, treeMenu, freeRecorders);
     9082
    90149083    if ((ctx != GetPlayer(ctx, 0)))
    90159084        return;
    90169085
     
    91619230    new OSDGenericTree(s_item, "120 " + tr("minutes"), "TOGGLESLEEP120");
    91629231}
    91639232
    9164 void TV::FillMenuLiveTV(OSDGenericTree *treeMenu)
     9233/// \brief Constructs Picture-X-Picture portion of menu
     9234void TV::FillMenuPxP(
     9235    const PlayerContext *ctx, OSDGenericTree *treeMenu, bool freeRecorders)
    91659236{
    9166     new OSDGenericTree(treeMenu, tr("Program Guide"), "GUIDE");
     9237    if (!ctx || !IsPIPSupported(ctx))
     9238        return;
    91679239
    9168     if (!gContext->GetNumSetting("JumpToProgramOSD", 1))
     9240    if ((player.size() <= 1) && !freeRecorders)
     9241        return;
     9242
     9243    OSDGenericTree *item =
     9244        new OSDGenericTree(treeMenu, tr("Picture-in-Picture"));
     9245
     9246    if (freeRecorders)
    91699247    {
    9170         OSDGenericTree *jtpo_item =
    9171             new OSDGenericTree(treeMenu, tr("Jump to Program"));
    9172         new OSDGenericTree(jtpo_item, tr("Recorded Program"), "JUMPREC");
    9173         if (lastProgram != NULL)
    9174             new OSDGenericTree(jtpo_item, lastProgram->title, "JUMPPREV");
     9248        if (player.size() <= kMaxPIPCount)
     9249            new OSDGenericTree(item, tr("Open Live TV PIP"), "CREATEPIPVIEW");
     9250        if (player.size() <= kMaxPBPCount)
     9251            new OSDGenericTree(item, tr("Open Live TV PBP"), "CREATEPBPVIEW");
    91759252    }
    91769253
     9254    if (player.size() <= kMaxPIPCount)
     9255        new OSDGenericTree(item, tr("Open Recording PIP"), "JUMPRECPIP");
     9256    if (player.size() <= kMaxPBPCount)
     9257        new OSDGenericTree(item, tr("Open Recording PBP"), "JUMPRECPBP");
     9258
     9259    if (player.size() <= 1)
     9260        return;
     9261
     9262    new OSDGenericTree(item, tr("Change Active Window"), "NEXTPIPWINDOW");
     9263
     9264    QString pipType  = (ctx->isPBP()) ? "PBP" : "PIP";
     9265    QString toggleMode = QString("TOGGLE%1MODE").arg(pipType);
     9266
     9267    bool isPBP = ctx->isPBP();
     9268    const PlayerContext *mctx = GetPlayer(ctx, 0);
     9269    QString pipClose = (isPBP) ? tr("Close PBP") : tr("Close PIP");
     9270    if (mctx == ctx)
     9271    {
     9272        if (player.size() > 2)
     9273            pipClose = (isPBP) ? tr("Close PBPs") : tr("Close PIPs");
     9274
     9275        new OSDGenericTree(item, pipClose, toggleMode);
     9276
     9277        if (player.size() == 2)
     9278            new OSDGenericTree(item, tr("Swap Windows"), "SWAPPIP");
     9279    }
     9280    else
     9281    {
     9282        new OSDGenericTree(item, pipClose, toggleMode);
     9283        new OSDGenericTree(item, tr("Swap Windows"), "SWAPPIP");
     9284    }
     9285
     9286    uint max_cnt = min(kMaxPBPCount, kMaxPIPCount);
     9287    if (player.size() <= max_cnt)
     9288    {
     9289        QString switchTo = (isPBP) ? tr("Switch to PIP") : tr("Switch to PBP");
     9290        new OSDGenericTree(item, switchTo, "TOGGLEPIPSTATE");
     9291    }
     9292}
     9293
     9294
     9295void TV::FillMenuLiveTV(OSDGenericTree *treeMenu)
     9296{
     9297    new OSDGenericTree(treeMenu, tr("Program Guide"), "GUIDE");
     9298
     9299    OSDGenericTree *jtpo_item =
     9300        new OSDGenericTree(treeMenu, tr("Jump to Program"));
     9301    new OSDGenericTree(jtpo_item, tr("Recorded Program"), "JUMPREC");
     9302    if (lastProgram != NULL)
     9303        new OSDGenericTree(jtpo_item, lastProgram->title, "JUMPPREV");
     9304
    91779305    if (!persistentbrowsemode)
    91789306        new OSDGenericTree(treeMenu, tr("Enable Browse Mode"), "TOGGLEBROWSE");
    91799307
     
    94039531    ReturnOSDLock(ctx, osd);
    94049532}
    94059533
    9406 void TV::SetJumpToProgram(QString progKey, int progIndex)
     9534bool TV::HandleJumpToProgramAction(
     9535    PlayerContext *ctx, const QStringList &actions)
    94079536{
    9408     QMap<QString,ProgramList>::Iterator Iprog;
    9409     Iprog = progLists.find(progKey);
    9410     ProgramList plist = *Iprog;
    9411     ProgramInfo *p = plist.at(progIndex);
    9412     VERBOSE(VB_IMPORTANT, QString("Switching to program: %1: %2")
    9413             .arg(p->title).arg(p->subtitle));
    9414     setLastProgram(p);
     9537    const PlayerContext *mctx = GetPlayer(ctx, 0);
     9538    TVState s = ctx->GetState();
     9539    if (has_action("JUMPPREV", actions) ||
     9540        (has_action("PREVCHAN", actions) && !StateIsLiveTV(s)))
     9541    {
     9542        if (PromptRecGroupPassword(ctx))
     9543        {
     9544            if (mctx == ctx)
     9545            {
     9546                ctx->LockDeleteNVP(__FILE__, __LINE__);
     9547                ctx->nvp->SetBookmark();
     9548                ctx->UnlockDeleteNVP(__FILE__, __LINE__);
     9549                jumpToProgram = true;
     9550                SetExitPlayer(true, true);
     9551            }
     9552            else
     9553            {
     9554                // TODO
     9555            }
     9556        }
     9557        return true;
     9558    }
     9559
     9560    QStringList::const_iterator it = actions.begin();
     9561    for (; it != actions.end(); ++it)
     9562    {
     9563        if ((*it).left(8) != "JUMPPROG")
     9564            continue;
     9565
     9566        const QString &action = *it;
     9567
     9568        bool ok;
     9569        QString progKey   = action.section(" ",1,-2);
     9570        uint    progIndex = action.section(" ",-1,-1).toUInt(&ok);
     9571        ProgramInfo *p = NULL;
     9572
     9573        if (!ok)
     9574        {
     9575            QMutexLocker locker(&progListsLock);
     9576            QMap<QString,ProgramList>::const_iterator it =
     9577                progLists.find(progKey);
     9578            if (it != progLists.end())
     9579            {
     9580                const ProgramInfo *tmp = (*it)[progIndex];
     9581                if (tmp)
     9582                    p = new ProgramInfo(*tmp);
     9583            }
     9584        }
     9585
     9586        if (!p)
     9587        {
     9588            VERBOSE(VB_IMPORTANT, LOC_ERR +
     9589                    QString("Failed to locate jump to program '%1' @ %2")
     9590                    .arg(progKey).arg(action.section(" ",-1,-1).toUInt(&ok)));
     9591            return true;
     9592        }
     9593
     9594        PIPState state = kPIPOff;
     9595        {
     9596            QMutexLocker locker(&timerIdLock);
     9597            state = jumpToProgramPIPState;
     9598        }
     9599
     9600        if (kPIPOff == state)
     9601        {
     9602            if (mctx == ctx)
     9603            {
     9604                VERBOSE(VB_GENERAL, LOC +
     9605                        QString("Switching to program: %1: %2")
     9606                        .arg(p->title).arg(p->subtitle));
     9607           
     9608                SetLastProgram(p);
     9609                ctx->LockDeleteNVP(__FILE__, __LINE__);
     9610                ctx->nvp->SetBookmark();
     9611                ctx->UnlockDeleteNVP(__FILE__, __LINE__);
     9612                jumpToProgram = true;
     9613                SetExitPlayer(true, true);
     9614            }
     9615            else
     9616            {
     9617                // TODO
     9618            }
     9619        }
     9620        else
     9621        {
     9622            QString type = (kPIPonTV == jumpToProgramPIPState) ? "PIP" : "PBP";
     9623            VERBOSE(VB_GENERAL, LOC + QString("Creating %1 with program: %2: %3")
     9624                    .arg(type).arg(p->title).arg(p->subtitle));
     9625
     9626            if (jumpToProgramPIPState == kPIPonTV)
     9627                CreatePIP(ctx, p);
     9628            else if (jumpToProgramPIPState == kPBPLeft)
     9629                CreatePBP(ctx, p);
     9630        }
     9631
     9632        delete p;
     9633
     9634        return true;
     9635    }
     9636
     9637    bool wants_jump = has_action("JUMPREC", actions);
     9638    bool wants_pip = !wants_jump && has_action("JUMPRECPIP", actions);
     9639    bool wants_pbp = !wants_jump && !wants_pip &&
     9640        has_action("JUMPRECPBP", actions);
     9641
     9642    if (!wants_jump && !wants_pip && !wants_pbp)
     9643        return false;
     9644
     9645    {
     9646        QMutexLocker locker(&timerIdLock);
     9647        jumpToProgramPIPState = wants_pip ? kPIPonTV :
     9648            (wants_pbp ? kPBPLeft : kPIPOff);
     9649    }
     9650
     9651    if (db_jump_prefer_osd && (StateIsPlaying(s) || StateIsLiveTV(s)))
     9652    {
     9653        QMutexLocker locker(&timerIdLock);
     9654        if (jumpMenuTimerId)
     9655            KillTimer(jumpMenuTimerId);
     9656        jumpMenuTimerId = StartTimer(1, __LINE__);
     9657    }
     9658    else if (RunPlaybackBoxPtr)
     9659        EditSchedule(ctx, kPlaybackBox);
     9660    else
     9661        VERBOSE(VB_IMPORTANT, "Failed to open jump to program GUI");
     9662
     9663    return true;
    94159664}
    94169665
    94179666void TV::ToggleSleepTimer(const PlayerContext *ctx, const QString &time)
     
    976910018
    977010019    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    977110020
    9772     if (isDVD && (!gContext->GetNumSetting("EnableDVDBookmark", 0) ||
    9773                   ctx->buffer->DVD()->GetTotalTimeOfTitle() < 120))
    9774     {
    9775         return false;
    9776     }
    9777 
    9778     return true;
     10021    return (!isDVD || (db_use_dvd_bookmark &&
     10022                       ctx->buffer->DVD()->GetTotalTimeOfTitle() >= 120));
    977910023}
    978010024
    978110025/* \fn TV::IsDeleteAllowed(const PlayerContext*) const
     
    991710161            dialogname == "exitplayoptions");
    991810162}
    991910163
    9920 void TV::setLastProgram(ProgramInfo *rcinfo)
     10164void TV::SetLastProgram(ProgramInfo *rcinfo)
    992110165{
     10166    QMutexLocker locker(&lastProgramLock);
     10167
    992210168    if (lastProgram)
    992310169        delete lastProgram;
    992410170
     
    992810174        lastProgram = NULL;
    992910175}
    993010176
     10177ProgramInfo *TV::GetLastProgram(void) const
     10178{
     10179    QMutexLocker locker(&lastProgramLock);
     10180    if (lastProgram)
     10181        return new ProgramInfo(*lastProgram);
     10182    return NULL;
     10183}
     10184
    993110185QString TV::GetRecordingGroup(int player_idx) const
    993210186{
    993310187    QString ret = QString::null;
     
    1002210276    treeMenu = new OSDGenericTree(NULL, "treeMenu");
    1002310277
    1002410278    // Build jumpMenu of recorded program titles
    10025     ProgramInfo *p;
     10279    QMutexLocker locker(&progListsLock);
    1002610280    progLists.clear();
    10027     vector<ProgramInfo *> *infoList;
    10028     infoList = RemoteGetRecordedList(false);
     10281    vector<ProgramInfo *> *infoList = RemoteGetRecordedList(false);
    1002910282
    1003010283    //bool LiveTVInAllPrograms = gContext->GetNumSetting("LiveTVInAllPrograms",0);
    1003110284    if (infoList)
    1003210285    {
    1003310286        PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    1003410287        actx->LockPlayingInfo(__FILE__, __LINE__);
    10035         vector<ProgramInfo *>::iterator i = infoList->begin();
    10036         for ( ; i != infoList->end(); i++)
     10288        vector<ProgramInfo *>::const_iterator it = infoList->begin();
     10289        for ( ; it != infoList->end(); it++)
    1003710290        {
    10038             p = *i;
    1003910291            //if (p->recgroup != "LiveTV" || LiveTVInAllPrograms)
    10040             if (p->recgroup == actx->playingInfo->recgroup)
    10041                 progLists[p->title].prepend(p);
     10292            if ((*it)->recgroup == actx->playingInfo->recgroup)
     10293                progLists[(*it)->title].push_front(new ProgramInfo(*(*it)));
    1004210294        }
    1004310295        actx->UnlockPlayingInfo(__FILE__, __LINE__);
    1004410296        ReturnPlayerLock(actx);
    1004510297
    10046         QMap<QString,ProgramList>::Iterator Iprog;
     10298        QMap<QString,ProgramList>::const_iterator Iprog;
    1004710299        for (Iprog = progLists.begin(); Iprog != progLists.end(); Iprog++)
    1004810300        {
    10049             ProgramList plist = *Iprog;
     10301            const ProgramList &plist = *Iprog;
    1005010302            int progIndex = plist.count();
    1005110303            if (progIndex == 1)
    1005210304            {
     
    1006110313
    1006210314                for (int i = 0; i < progIndex; i++)
    1006310315                {
    10064                     p = plist.at(i);
    10065                     if (p->subtitle.size())
     10316                    const ProgramInfo *p = plist[i];
     10317                    if (!p->subtitle.isEmpty())
    1006610318                        new OSDGenericTree(j_item, p->subtitle,
    1006710319                            QString("JUMPPROG %1 %2").arg(Iprog.key()).arg(i));
    1006810320                    else
     
    1007210324            }
    1007310325        }
    1007410326    }
     10327    while (!infoList->empty())
     10328    {
     10329        delete infoList->back();
     10330        infoList->pop_back();
     10331    }
     10332    delete infoList;
    1007510333
    1007610334    PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
    1007710335    OSD *osd = GetOSDLock(actx);
     
    1009310351        }
    1009410352    }
    1009510353    ReturnOSDLock(actx, osd);
    10096 
     10354    ReturnPlayerLock(actx);
    1009710355}
    1009810356
    1009910357void TV::RestoreScreenSaver(const PlayerContext *ctx)
     
    1010410362
    1010510363void TV::InitUDPNotifyEvent(void)
    1010610364{
    10107     uint udp_port = gContext->GetNumSetting("UDPNotifyPort");
    10108     if (udp_port && !udpnotify)
     10365    if (db_udpnotify_port && !udpnotify)
    1010910366    {
    10110         udpnotify = new UDPNotify(udp_port);
     10367        udpnotify = new UDPNotify(db_udpnotify_port);
    1011110368        connect(udpnotify,
    1011210369                SIGNAL(AddUDPNotifyEvent(
    1011310370                        const QString&,const UDPNotifyOSDSet*)),
     
    1024210499{
    1024310500    playerLock.lockForWrite();
    1024410501
     10502    //VERBOSE(VB_IMPORTANT, LOC_WARN +
     10503    //        QString("GetPlayerWriteLock(%1,%2,%3) size(%4)")
     10504    //        .arg(which).arg(file).arg(location).arg(player.size()));
     10505
    1024510506    if ((which >= (int)player.size()))
    1024610507    {
    1024710508        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    1025710518{
    1025810519    playerLock.lockForRead();
    1025910520
     10521    //VERBOSE(VB_IMPORTANT, LOC_WARN +
     10522    //        QString("GetPlayerReadLock(%1,%2,%3) size(%4)")
     10523    //        .arg(which).arg(file).arg(location).arg(player.size()));
     10524
    1026010525    if ((which >= (int)player.size()))
    1026110526    {
    1026210527        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    1027310538{
    1027410539    playerLock.lockForRead();
    1027510540
     10541    //VERBOSE(VB_IMPORTANT, LOC_WARN +
     10542    //        QString("GetPlayerReadLock(%1,%2,%3) const size(%4)")
     10543    //        .arg(which).arg(file).arg(location).arg(player.size()));
     10544
    1027610545    if ((which >= (int)player.size()))
    1027710546    {
    1027810547        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    1032010589
    1032110590void TV::ReturnPlayerLock(PlayerContext *&ctx)
    1032210591{
     10592    //VERBOSE(VB_IMPORTANT, LOC_WARN +
     10593    //        QString("ReturnPlayerLock() size(%4)")
     10594    //        .arg(player.size()));
     10595
    1032310596    playerLock.unlock();
    1032410597    ctx = NULL;
    1032510598}
    1032610599
    1032710600void TV::ReturnPlayerLock(const PlayerContext *&ctx) const
    1032810601{
     10602    //VERBOSE(VB_IMPORTANT, LOC_WARN +
     10603    //        QString("ReturnPlayerLock() const size(%4)")
     10604    //        .arg(player.size()));
     10605
    1032910606    playerLock.unlock();
    1033010607    ctx = NULL;
    1033110608}
  • libs/libmythtv/videoout_null.cpp

     
    217217
    218218void VideoOutputNull::ProcessFrame(VideoFrame *frame, OSD *osd,
    219219                                   FilterChain *filterList,
    220                                    NuppelVideoPlayer *pipPlayer)
     220                                   const PIPMap &pipPlayers)
    221221{
    222222    (void)frame;
    223223    (void)osd;
    224224    (void)filterList;
    225     (void)pipPlayer;
     225    (void)pipPlayers;
    226226}
  • libs/libmythtv/videoouttypes.h

     
    1111    kPIPOff = 0,
    1212    kPIPonTV,
    1313    kPIPStandAlone,
    14     kPIPSwap,
    1514    kPBPLeft,
    1615    kPBPRight,
    17     kPBPSwap,
    18     kPIPToPBP,
    19     kPBPToPIP,
    20     kPBPToggle
    2116} PIPState;
    2217
    2318typedef enum PIPLocation
  • libs/libmythtv/videooutbase.cpp

     
    267267    pip_desired_display_size(160,128),  pip_display_size(0,0),
    268268    pip_video_size(0,0),
    269269    pip_tmp_buf(NULL),                  pip_tmp_buf2(NULL),
    270     pip_scaling_context(NULL),          pad_pip_window(false),
     270    pip_scaling_context(NULL),
    271271
    272272    // Video resizing (for ITV)
    273273    vsz_enabled(false),
     
    788788/*
    789789 * \brief Determines PIP Window size and Position.
    790790 */
    791 QRect VideoOutput::GetPIPRect(int location,
    792                     NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
     791QRect VideoOutput::GetPIPRect(
     792    PIPLocation location, NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
    793793{
    794794    return windows[0].GetPIPRect(location, pipplayer, do_pixel_adj);
    795795}
     
    799799 * \brief Sets up Picture in Picture image resampler.
    800800 * \param pipwidth  input width
    801801 * \param pipheight input height
    802  * \sa ShutdownPipResize(), ShowPIP(VideoFrame*,NuppelVideoPlayer*)
     802 * \sa ShutdownPipResize(), ShowPIPs(VideoFrame*,const PIPMap&)
    803803 */
    804804void VideoOutput::DoPipResize(int pipwidth, int pipheight)
    805805{
     
    825825 * \fn VideoOutput::ShutdownPipResize()
    826826 * \brief Shuts down Picture in Picture image resampler.
    827827 * \sa VideoOutput::DoPipResize(int,int),
    828  *     ShowPIP(VideoFrame*,NuppelVideoPlayer*)
     828 *     ShowPIPs(VideoFrame*,const PIPMap&)
    829829 */
    830830void VideoOutput::ShutdownPipResize(void)
    831831{
     
    851851    pip_display_size = QSize(0,0);
    852852}
    853853
     854void VideoOutput::ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers)
     855{
     856    PIPMap::const_iterator it = pipPlayers.begin();
     857    for (; it != pipPlayers.end(); ++it)
     858        ShowPIP(frame, it.key(), *it);
     859}
     860
    854861/**
    855  * \fn VideoOutput::ShowPIP(VideoFrame*,NuppelVideoPlayer*)
     862 * \fn VideoOutput::ShowPIP(VideoFrame*,NuppelVideoPlayer*,PIPLocation)
    856863 * \brief Composites PiP image onto a video frame.
    857  * Note: This only works with memory backed VideoFrames,
    858  *       that is not XvMC.
     864 *
     865 *  Note: This only works with memory backed VideoFrames,
     866 *        that is not XvMC, OpenGL, VDPAU, etc.
     867 *
    859868 * \param frame     Frame to composite PiP onto.
    860869 * \param pipplayer Picture-in-Picture NVP.
     870 * \param loc       Location of this PiP on the frame.
    861871 */
    862 void VideoOutput::ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
     872void VideoOutput::ShowPIP(VideoFrame        *frame,
     873                          NuppelVideoPlayer *pipplayer,
     874                          PIPLocation        loc)
    863875{
    864876    if (!pipplayer)
    865877        return;
    866878
    867     int pipw, piph;
    868 
    869     const float video_aspect = windows[0].GetVideoAspect();
     879    const float video_aspect           = windows[0].GetVideoAspect();
     880    const QRect display_video_rect     = windows[0].GetDisplayVideoRect();
     881    const QRect video_rect             = windows[0].GetVideoRect();
     882    const QRect display_visible_rect   = windows[0].GetDisplayVisibleRect();
     883    const float overriden_video_aspect = windows[0].GetOverridenVideoAspect();
     884    const QSize video_disp_dim         = windows[0].GetVideoDispDim();
     885    const int   pip_size               = windows[0].GetPIPSize();
    870886    const AspectOverrideMode aspectoverride = windows[0].GetAspectOverride();
    871     const QRect display_video_rect = windows[0].GetDisplayVideoRect();
    872     const QRect video_rect = windows[0].GetVideoRect();
    873     const QRect display_visible_rect = windows[0].GetDisplayVisibleRect();
    874     const float overriden_video_aspect = windows[0].GetOverridenVideoAspect();
    875     const QSize video_disp_dim = windows[0].GetVideoDispDim();
    876887
    877     VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
    878     float pipVideoAspect = pipplayer->GetVideoAspect();
    879     QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
    880     uint  pipVideoWidth  = pipVideoDim.width();
    881     uint  pipVideoHeight = pipVideoDim.height();
     888    int pipw, piph;
     889    VideoFrame *pipimage       = pipplayer->GetCurrentFrame(pipw, piph);
     890    const bool  pipActive      = pipplayer->IsPIPActive();
     891    const float pipVideoAspect = pipplayer->GetVideoAspect();
     892    const QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
     893    const uint  pipVideoWidth  = pipVideoDim.width();
     894    const uint  pipVideoHeight = pipVideoDim.height();
    882895
    883896    // If PiP is not initialized to values we like, silently ignore the frame.
    884897    if ((video_aspect <= 0) || (pipVideoAspect <= 0) ||
     
    890903    }
    891904
    892905    // set height
    893     int tmph = (int) ((frame->height * windows[0].GetPIPSize()) * 0.01f);
     906    int tmph = (int) ((frame->height * pip_size) * 0.01f);
    894907    pip_desired_display_size.setHeight((tmph >> 1) << 1);
    895908
    896909    // adjust for letterbox modes...
     
    944957
    945958            img_resample(pip_scaling_context, &img_out, &img_in);
    946959         
    947             if (pad_pip_window)
     960            if (pipActive)
    948961            {
    949962                AVPicture img_padded;
    950963                avpicture_fill(
     
    952965                    pip_display_size.width(), pip_display_size.height());
    953966
    954967                int color[3] = { 20, 0, 200 }; //deep red YUV format
    955                 av_picture_pad(&img_padded, &img_out, pip_display_size.height(),
    956                         pip_display_size.width(), PIX_FMT_YUV420P, 10, 10,
    957                         10, 10, color);
     968                av_picture_pad(&img_padded, &img_out,
     969                               pip_display_size.height(),
     970                               pip_display_size.width(),
     971                               PIX_FMT_YUV420P, 10, 10, 10, 10, color);
    958972               
    959973                pipbuf = pip_tmp_buf2;
    960974            }
    961975            else
     976            {
    962977                pipbuf = pip_tmp_buf;
     978            }
    963979
    964980            pipw = pip_display_size.width();
    965981            piph = pip_display_size.height();
    966982
    967983            init(&pip_tmp_image,
    968                     FMT_YV12,
    969                     pipbuf,
    970                     pipw, piph,
    971                     pipimage->bpp, sizeof(pipbuf));
     984                 FMT_YV12,
     985                 pipbuf,
     986                 pipw, piph,
     987                 pipimage->bpp, sizeof(pipbuf));
    972988        }
    973989    }
    974990
    975991    // Figure out where to put the Picture-in-Picture window
    976992    int xoff = 0;
    977993    int yoff = 0;
    978     switch (windows[0].GetPIPLocation())
     994    switch (loc)
    979995    {
    980996        case kPIP_END:
    981997        case kPIPTopLeft:
    982                 xoff = 30 + letterXadj;
    983                 yoff = 40 + letterYadj;
    984                 break;
     998            xoff = 30 + letterXadj;
     999            yoff = 40 + letterYadj;
     1000            break;
    9851001        case kPIPBottomLeft:
    986                 xoff = 30 + letterXadj;
    987                 yoff = frame->height - piph - 40 - letterYadj;
    988                 break;
     1002            xoff = 30 + letterXadj;
     1003            yoff = frame->height - piph - 40 - letterYadj;
     1004            break;
    9891005        case kPIPTopRight:
    990                 xoff = frame->width  - pipw - 30 - letterXadj;
    991                 yoff = 40 + letterYadj;
    992                 break;
     1006            xoff = frame->width  - pipw - 30 - letterXadj;
     1007            yoff = 40 + letterYadj;
     1008            break;
    9931009        case kPIPBottomRight:
    994                 xoff = frame->width  - pipw - 30 - letterXadj;
    995                 yoff = frame->height - piph - 40 - letterYadj;
    996                 break;
     1010            xoff = frame->width  - pipw - 30 - letterXadj;
     1011            yoff = frame->height - piph - 40 - letterYadj;
     1012            break;
    9971013    }
    9981014
    9991015    uint xoff2[3]  = { xoff, xoff>>1, xoff>>1 };
     
    10061022        for (uint h = 2; h < height[p]; h++)
    10071023        {
    10081024            memcpy((frame->buf + frame->offsets[p]) + (h + yoff2[p]) *
    1009                     frame->pitches[p] + xoff2[p],
    1010                     (pip_tmp_image.buf + pip_tmp_image.offsets[p]) + h *
    1011                     pip_tmp_image.pitches[p], pip_tmp_image.pitches[p]);
     1025                   frame->pitches[p] + xoff2[p],
     1026                   (pip_tmp_image.buf + pip_tmp_image.offsets[p]) + h *
     1027                   pip_tmp_image.pitches[p], pip_tmp_image.pitches[p]);
    10121028        }
    10131029    }
    10141030
     
    10201036 * \brief Sets up Picture in Picture image resampler.
    10211037 * \param inDim  input width and height
    10221038 * \param outDim output width and height
    1023  * \sa ShutdownPipResize(), ShowPIP(VideoFrame*,NuppelVideoPlayer*)
     1039 * \sa ShutdownPipResize(), ShowPIPs(VideoFrame*,const PIPMap&)
    10241040 */
    10251041void VideoOutput::DoVideoResize(const QSize &inDim, const QSize &outDim)
    10261042{
  • libs/libmythtv/videooutwindow.h

     
    7070    float    GetMzScaleV(void)           const { return mz_scale_v;      }
    7171    float    GetMzScaleH(void)           const { return mz_scale_h;      }
    7272    QPoint   GetMzMove(void)             const { return mz_move;         }
    73     PIPLocation GetPIPLocation(void)     const { return db_pip_location; }
    7473    int         GetPIPSize(void)         const { return db_pip_size;     }
    7574    PIPState    GetPIPState(void)        const { return pip_state;       }
    7675    QSize  GetVideoDispDim(void)         const { return video_disp_dim;  }
     
    9695        { return tmp_display_visible_rect; }
    9796    QRect GetVisibleOSDBounds(float&, float&, float) const;
    9897    QRect GetTotalOSDBounds(void) const;
    99     QRect GetPIPRect(int                location,
     98
     99    QRect GetPIPRect(PIPLocation        location,
    100100                     NuppelVideoPlayer *pipplayer    = NULL,
    101101                     bool               do_pixel_adj = true) const;
    102102
     
    112112    QPoint  db_move;          ///< Percentage move from database
    113113    float   db_scale_horiz;   ///< Horizontal Overscan/Underscan percentage
    114114    float   db_scale_vert;    ///< Vertical Overscan/Underscan percentage
    115     PIPLocation db_pip_location;
    116115    int     db_pip_size;      ///< percentage of full window to use for PiP
    117116    bool    db_scaling_allowed;///< disable this to prevent overscan/underscan
    118117
  • libs/libmythtv/playercontext.h

     
    6262    bool StartPIPPlayer(TV *tv, TVState desiredState);
    6363    void PIPTeardown(void);
    6464    bool isPIP(void) const
    65         { return (pipState > kPIPOff && pipState < kPBPLeft); }
     65        { return (kPIPonTV == pipState) || (kPIPStandAlone == pipState); }
    6666    bool isPBP(void) const
    67         { return (pipState > kPIPStandAlone && pipState < kPBPSwap); }
     67        { return (kPBPLeft == pipState) || (kPBPRight      == pipState); }
    6868    bool isMainVideo(void) const
    69         { return (pipState == kPIPOff || pipState == kPBPLeft); }
     69        { return (kPIPOff  == pipState) || (kPBPLeft       == pipState); }
    7070    void DrawARGBFrame(QPainter *p);
    7171    QRect GetStandAlonePIPRect(void);
    72     QString PIPLocationToString(void);
    73     QString PIPStateToString(void);
    7472    PIPState GetPIPState(void) const { return pipState; }
    7573    void SetNullVideo(bool setting) { useNullVideo = setting; }
    7674    bool UseNullVideo(void) const { return useNullVideo; }
     75    bool IsNVPChangingBuffers(void) const { return nvpUnsafe; }
    7776
    78 
    7977    void    PushPreviousChannel(void);
    8078    QString PopPreviousChannel(void);
    8179    QString GetPreviousChannel(void) const;
     
    9088    void LockState(void) const;
    9189    void UnlockState(void) const;
    9290    bool InStateChange(void) const;
    93     void ChangeState(TVState newState);
    94     void ForceNextStateNone(void);
     91    void ChangeState(TVState newState, int line);
     92    void ForceNextStateNone(int line);
    9593    TVState DequeueNextState(void);
    9694    TVState GetState(void) const;
    9795    /// This is set if the player encountered some irrecoverable error.
     
    113111    void SetPlayGroup(const QString &group);
    114112    void SetPseudoLiveTV(const ProgramInfo *pi, PseudoState new_state);
    115113    void SetPIPState(PIPState change) { pipState = change; }
     114    void SetNVPChangingBuffers(bool val) { nvpUnsafe = val; }
    116115    void ResizePIPWindow(void);
    117116
    118117
    119118  public:
    120119    NuppelVideoPlayer  *nvp;
     120    volatile bool       nvpUnsafe;
    121121    RemoteEncoder      *recorder;
    122122    LiveTVChain        *tvchain;
    123123    RingBuffer         *buffer;
  • libs/libmythtv/videoout_xv.h

     
    7272
    7373    void ProcessFrame(VideoFrame *frame, OSD *osd,
    7474                      FilterChain *filterList,
    75                       NuppelVideoPlayer *pipPlayer);
     75                      const PIPMap &pipPlayers);
     76
    7677    void PrepareFrame(VideoFrame*, FrameScanType);
    7778    void DrawSlice(VideoFrame*, int x, int y, int w, int h);
    7879    void Show(FrameScanType);
     
    114115        { return OpenGL <= VideoOutputSubType(); }
    115116
    116117    void CheckFrameStates(void);
    117     QRect GetPIPRect(int location,
    118                     NuppelVideoPlayer *pipplayer = NULL,
    119                     bool do_pixel_adj = true) const;
    120118
     119    virtual QRect GetPIPRect(PIPLocation        location,
     120                             NuppelVideoPlayer *pipplayer = NULL,
     121                             bool               do_pixel_adj = true) const;
     122
    121123    virtual void ShutdownVideoResize(void);
    122124
    123125    // OpenGL
     
    162164    void DoneDisplayingFrame(void);
    163165
    164166    void ProcessFrameVDPAU(VideoFrame *frame, OSD *osd,
    165                            NuppelVideoPlayer *pipPlayer);
     167                           const PIPMap &pipPlayers);
    166168    void ProcessFrameXvMC(VideoFrame *frame, OSD *osd);
    167169    void ProcessFrameOpenGL(VideoFrame *frame, OSD *osd,
    168170                            FilterChain *filterList,
    169                             NuppelVideoPlayer *pipPlayer);
     171                            const PIPMap &pipPlayers);
    170172    void ProcessFrameMem(VideoFrame *frame, OSD *osd,
    171173                         FilterChain *filterList,
    172                          NuppelVideoPlayer *pipPlayer);
     174                         const PIPMap &pipPlayers);
    173175
    174176    void PrepareFrameVDPAU(VideoFrame *, FrameScanType);
    175177    void PrepareFrameXvMC(VideoFrame *, FrameScanType);
     
    181183    void ShowXvMC(FrameScanType scan);
    182184    void ShowXVideo(FrameScanType scan);
    183185
    184     void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
     186    virtual void ShowPIP(VideoFrame        *frame,
     187                         NuppelVideoPlayer *pipplayer,
     188                         PIPLocation        loc);
     189
    185190    virtual int DisplayOSD(VideoFrame *frame, OSD *osd,
    186191                           int stride = -1, int revision = -1);
    187192
     
    307312    QWaitCondition       gl_context_wait;
    308313    OpenGLContextGLX    *gl_context;
    309314    OpenGLVideo         *gl_videochain;
    310     OpenGLVideo         *gl_pipchain;
     315    QMap<NuppelVideoPlayer*,OpenGLVideo*> gl_pipchains;
     316    QMap<NuppelVideoPlayer*,bool>         gl_pip_ready;
     317    OpenGLVideo         *gl_pipchain_active;
    311318    OpenGLVideo         *gl_osdchain;
    312319    bool                 gl_use_osd_opengl2;
    313     bool                 gl_pip_ready;
    314320    bool                 gl_osd_ready;
    315321
    316322    // Chromakey OSD info
  • libs/libmythtv/videoout_xv.cpp

     
    169169
    170170      gl_context_lock(QMutex::Recursive),
    171171      gl_context_creator(NULL), gl_context(NULL),
    172       gl_videochain(NULL), gl_pipchain(NULL),
     172      gl_videochain(NULL), gl_pipchain_active(NULL),
    173173      gl_osdchain(NULL),
    174174
    175175      gl_use_osd_opengl2(false),
    176       gl_pip_ready(false),
    177176      gl_osd_ready(false),
    178177
    179178
     
    27312730        delete gl_videochain;
    27322731        gl_videochain = NULL;
    27332732    }
    2734     if (gl_pipchain)
     2733    while (!gl_pipchains.empty())
    27352734    {
    2736         delete gl_pipchain;
    2737         gl_pipchain = NULL;
     2735        delete *gl_pipchains.begin();
     2736        gl_pipchains.erase(gl_pipchains.begin());
    27382737    }
    27392738    if (gl_osdchain)
    27402739    {
     
    27492748    }
    27502749
    27512750    gl_use_osd_opengl2 = false;
    2752     gl_pip_ready = false;
     2751    gl_pip_ready.clear();
    27532752    gl_osd_ready = false;
    27542753
    27552754    // end OpenGL stuff
     
    31623161
    31633162    gl_videochain->PrepareFrame(t, m_deinterlacing, framesPlayed, false);
    31643163
    3165     if (gl_pip_ready && gl_pipchain)
    3166         gl_pipchain->PrepareFrame(t, m_deinterlacing, framesPlayed,
    3167                                   pad_pip_window);
     3164    QMap<NuppelVideoPlayer*,OpenGLVideo*>::iterator it = gl_pipchains.begin();
     3165    for (; it != gl_pipchains.end(); ++it)
     3166    {
     3167        if (gl_pip_ready[it.key()])
     3168        {
     3169            bool active = gl_pipchain_active == *it;
     3170            (*it)->PrepareFrame(t, m_deinterlacing, framesPlayed, active);
     3171        }
     3172    }
    31683173
    31693174    if (gl_osd_ready && gl_osdchain)
    31703175        gl_osdchain->PrepareFrame(t, m_deinterlacing, framesPlayed, false);
     
    35823587    X11S(XSync(XJ_disp, False));
    35833588}
    35843589
    3585 void VideoOutputXv::ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
     3590void VideoOutputXv::ShowPIP(VideoFrame        *frame,
     3591                            NuppelVideoPlayer *pipplayer,
     3592                            PIPLocation        loc)
    35863593{
     3594    if (VideoOutputSubType() >= XVideoMC &&
     3595        VideoOutputSubType() <= XVideoVLD)
     3596    {
     3597        return;
     3598    }
     3599
    35873600    if (VideoOutputSubType() != OpenGL &&
    35883601        VideoOutputSubType() != XVideoVDPAU)
    35893602    {
    3590         VideoOutput::ShowPIP(frame, pipplayer);
     3603        VideoOutput::ShowPIP(frame, pipplayer, loc);
    35913604        return;
    35923605    }
    35933606
    35943607    (void) frame;
    35953608
    3596     gl_pip_ready = false;
    3597 
    35983609    if (!pipplayer)
    35993610        return;
    36003611
    36013612    int pipw, piph;
    3602     VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
    3603     float pipVideoAspect = pipplayer->GetVideoAspect();
    3604     QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
    3605     uint  pipVideoWidth  = pipVideoDim.width();
    3606     uint  pipVideoHeight = pipVideoDim.height();
     3613    VideoFrame *pipimage       = pipplayer->GetCurrentFrame(pipw, piph);
     3614    const bool  pipActive      = pipplayer->IsPIPActive();
     3615    const float pipVideoAspect = pipplayer->GetVideoAspect();
     3616    const QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
     3617    const uint  pipVideoWidth  = pipVideoDim.width();
     3618    const uint  pipVideoHeight = pipVideoDim.height();
    36073619
    36083620    // If PiP is not initialized to values we like, silently ignore the frame.
    36093621    if ((pipVideoAspect <= 0) || !pipimage ||
     
    36133625        return;
    36143626    }
    36153627
    3616     QRect position = GetPIPRect(windows[0].GetPIPLocation(), pipplayer);
     3628    QRect position = GetPIPRect(loc, pipplayer);
    36173629    QRect dvr = GetTotalVisibleRect();
    36183630 
    36193631#ifdef USING_VDPAU
     
    36253637    }
    36263638#endif // USING_VDPAU
    36273639
     3640    gl_pip_ready[pipplayer] = false;
     3641    OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
    36283642    if (!gl_pipchain)
    36293643    {
    36303644        VERBOSE(VB_PLAYBACK, LOC + "Initialise PiP.");
    3631         gl_pipchain = new OpenGLVideo();
     3645        gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
    36323646        bool success = gl_pipchain->Init(gl_context, db_use_picture_controls,
    36333647                     QSize(pipVideoWidth, pipVideoHeight),
    36343648                     dvr, position,
     
    36483662    {
    36493663        VERBOSE(VB_PLAYBACK, LOC + "Re-initialise PiP.");
    36503664        delete gl_pipchain;
    3651         gl_pipchain = new OpenGLVideo();
     3665        gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
    36523666        bool success = gl_pipchain->Init(
    36533667            gl_context, db_use_picture_controls,
    36543668            QSize(pipVideoWidth, pipVideoHeight),
     
    36683682                              QRect(0, 0, pipVideoWidth, pipVideoHeight));
    36693683    gl_pipchain->UpdateInputFrame(pipimage);
    36703684
    3671     gl_pip_ready = true;
     3685    gl_pip_ready[pipplayer] = true;
    36723686
     3687    if (pipActive)
     3688        gl_pipchain_active = gl_pipchain;
     3689
    36733690    pipplayer->ReleaseCurrentFrame(pipimage);
    36743691}
    36753692
     
    40404057}
    40414058
    40424059void VideoOutputXv::ProcessFrameVDPAU(VideoFrame *frame, OSD *osd,
    4043                                       NuppelVideoPlayer *pipPlayer)
     4060                                      const PIPMap &pipPlayers)
    40444061{
    40454062    DisplayOSD(frame, osd);
    4046     ShowPIP(frame, pipPlayer);
     4063    ShowPIPs(frame, pipPlayers);
    40474064}
    40484065
    40494066void VideoOutputXv::ProcessFrameXvMC(VideoFrame *frame, OSD *osd)
     
    42524269
    42534270void VideoOutputXv::ProcessFrameOpenGL(VideoFrame *frame, OSD *osd,
    42544271                                       FilterChain *filterList,
    4255                                        NuppelVideoPlayer *pipPlayer)
     4272                                       const PIPMap &pipPlayers)
    42564273{
    42574274    (void) osd;
    42584275    (void) filterList;
    4259     (void) pipPlayer;
     4276    (void) pipPlayers;
    42604277
    42614278    if (!gl_videochain || !gl_context)
    42624279        return;
     
    42834300   
    42844301    if (!windows[0].IsEmbedding())
    42854302    {
    4286         ShowPIP(frame, pipPlayer);
     4303        gl_pipchain_active = NULL;
     4304        ShowPIPs(frame, pipPlayers);
    42874305        if (osd)
    42884306            DisplayOSD(frame, osd);
    42894307    }
     
    42964314
    42974315void VideoOutputXv::ProcessFrameMem(VideoFrame *frame, OSD *osd,
    42984316                                    FilterChain *filterList,
    4299                                     NuppelVideoPlayer *pipPlayer)
     4317                                    const PIPMap &pipPlayers)
    43004318{
    43014319    bool deint_proc = m_deinterlacing && (m_deintFilter != NULL);
    43024320    bool pauseframe = false;
     
    43244342            m_deintFilter->ProcessFrame(frame);
    43254343    }
    43264344
    4327     ShowPIP(frame, pipPlayer);
     4345    ShowPIPs(frame, pipPlayers);
    43284346
    43294347    if (osd && !windows[0].IsEmbedding())
    43304348    {
     
    43504368// this is documented in videooutbase.cpp
    43514369void VideoOutputXv::ProcessFrame(VideoFrame *frame, OSD *osd,
    43524370                                 FilterChain *filterList,
    4353                                  NuppelVideoPlayer *pipPlayer)
     4371                                 const PIPMap &pipPlayers)
    43544372{
    43554373    if (IsErrored())
    43564374    {
     
    43594377    }
    43604378
    43614379    if (VideoOutputSubType() == XVideoVDPAU)
    4362         ProcessFrameVDPAU(frame, osd, pipPlayer);
     4380        ProcessFrameVDPAU(frame, osd, pipPlayers);
    43634381    else if (VideoOutputSubType() == OpenGL)
    4364         ProcessFrameOpenGL(frame, osd, filterList, pipPlayer);
     4382        ProcessFrameOpenGL(frame, osd, filterList, pipPlayers);
    43654383    else if (VideoOutputSubType() <= XVideo)
    4366         ProcessFrameMem(frame, osd, filterList, pipPlayer);
     4384        ProcessFrameMem(frame, osd, filterList, pipPlayers);
    43674385    else
    43684386        ProcessFrameXvMC(frame, osd);
    43694387}
     
    47214739#endif // USING_XVMC
    47224740}
    47234741
    4724 QRect VideoOutputXv::GetPIPRect(int location, NuppelVideoPlayer *pipplayer,
    4725                                 bool do_pixel_adj) const
     4742QRect VideoOutputXv::GetPIPRect(PIPLocation        location,
     4743                                NuppelVideoPlayer *pipplayer,
     4744                                bool               do_pixel_adj) const
    47264745{
    47274746    (void)do_pixel_adj;
    47284747
  • libs/libmythtv/programinfo.h

     
    11#ifndef PROGRAMINFO_H_
    22#define PROGRAMINFO_H_
    33
    4 #include "recordingtypes.h"
    5 #include "mythdbcon.h"
     4// C++ headers
     5#include <vector>
     6#include <deque>
     7using namespace std;
    68
    7 #include <qstring.h>
    8 #include <qdatetime.h>
    9 #include <qmap.h>
    109#include <QStringList>
     10#include <QDateTime>
     11#include <QRegExp>
     12#include <QMap>
    1113
    12 #include <qregexp.h>
     14#include "recordingtypes.h"
     15#include "mythdbcon.h"
    1316
    14 #include <vector>
    15 #include <list>
    16 using namespace std;
    17 
    1817typedef QMap<long long, long long> frm_pos_map_t;
    1918typedef QMap<long long, int> frm_dir_map_t;
    2019
     
    458457    ProgramList(bool auto_delete = true) : autodelete(auto_delete) {}
    459458    ~ProgramList();
    460459
    461     typedef list<ProgramInfo*>::iterator iterator;
    462     typedef list<ProgramInfo*>::const_iterator const_iterator;
     460    typedef deque<ProgramInfo*>::iterator iterator;
     461    typedef deque<ProgramInfo*>::const_iterator const_iterator;
    463462
    464463    ProgramInfo *operator[](uint index);
     464    const ProgramInfo *operator[](uint index) const;
    465465    bool operator==(const ProgramList &b) const;
    466466
    467467    bool FromScheduler(bool &hasConflicts, QString altTable = "", int recordid=-1);
     
    495495    const_iterator begin(void) const { return pglist.begin(); }
    496496    const_iterator end(void)   const { return pglist.end();   }
    497497
    498     void sort(bool (&f)(const ProgramInfo*, const ProgramInfo*))
    499         { pglist.sort(f); }
     498    void sort(bool (&f)(const ProgramInfo*, const ProgramInfo*));
    500499    bool empty(void) const { return pglist.empty(); }
    501500    size_t size(void) const { return pglist.size(); }
    502501    void push_front(ProgramInfo *pginfo) { pglist.push_front(pginfo); }
     
    511510    void setAutoDelete(bool auto_delete) { autodelete = auto_delete; }
    512511
    513512  protected:
    514     list<ProgramInfo*> pglist;
     513    deque<ProgramInfo*> pglist;
    515514    bool autodelete;
    516515};
    517516
  • libs/libmythtv/programinfo.cpp

     
    1 #include <iostream>
     1// POSIX headers
    22#include <sys/types.h>
    33#include <unistd.h>
    4 #include <stdlib.h>
    54
     5// C headers
     6#include <cstdlib>
     7
     8// C++ headers
     9#include <iostream>
     10#include <algorithm>
     11using namespace std;
     12
     13// Qt headers
    614#include <QRegExp>
    715#include <QMap>
    816#include <QLayout>
     
    1119#include <QFile>
    1220#include <QFileInfo>
    1321
     22// MythTV headers
    1423#include "programinfo.h"
    1524#include "progdetails.h"
    1625#include "scheduledrecording.h"
     
    47494758
    47504759ProgramInfo *ProgramList::operator[](uint index)
    47514760{
    4752     iterator it = pglist.begin();
    4753     for (uint i = 0; i < index; i++, it++)
    4754     {
    4755         if (it == pglist.end())
    4756             return NULL;
    4757     }
    4758     if (it == pglist.end())
    4759         return NULL;
    4760     return *it;
     4761    if (index < pglist.size())
     4762        return pglist[index];
     4763    return NULL;
    47614764}
    47624765
     4766const ProgramInfo *ProgramList::operator[](uint index) const
     4767{
     4768    if (index < pglist.size())
     4769        return pglist[index];
     4770    return NULL;
     4771}
     4772
    47634773bool ProgramList::operator==(const ProgramList &b) const
    47644774{
    47654775    const_iterator it_a  = pglist.begin();
     
    48074817    pglist.clear();
    48084818}
    48094819
     4820void ProgramList::sort(bool (&f)(const ProgramInfo*, const ProgramInfo*))
     4821{
     4822    stable_sort(begin(), end(), f);
     4823}
     4824
    48104825bool ProgramList::FromScheduler(bool &hasConflicts, QString tmptable,
    48114826                                int recordid)
    48124827{
  • libs/libmythtv/videooutbase.h

     
    3030class VideoDisplayProfile;
    3131class OpenGLContextGLX;
    3232
     33typedef QMap<NuppelVideoPlayer*,PIPLocation> PIPMap;
     34
    3335extern "C" {
    3436struct ImgReSampleContext;
    3537}
     
    115117    // pass in null to use the pause frame, if it exists.
    116118    virtual void ProcessFrame(VideoFrame *frame, OSD *osd,
    117119                              FilterChain *filterList,
    118                               NuppelVideoPlayer *pipPlayer) = 0;
     120                              const PIPMap &pipPlayers) = 0;
    119121
    120122    /// \brief Tells video output that a full repaint is needed.
    121123    void ExposeEvent(void);
     
    228230    bool IsVideoScalingAllowed(void) const;
    229231
    230232    /// \brief returns QRect of PIP based on PIPLocation
    231     virtual QRect GetPIPRect(int location,
     233    virtual QRect GetPIPRect(PIPLocation location,
    232234                             NuppelVideoPlayer *pipplayer = NULL,
    233235                             bool do_pixel_adj = true) const;
    234236
    235237    virtual void SetPIPState(PIPState setting);
    236     virtual void PadPIPImage(bool change) { pad_pip_window = change; }
    237238
    238239    virtual QString GetOSDRenderer(void) const;
    239240
     
    245246                     int needprebuffer_normal, int needprebuffer_small,
    246247                     int keepprebuffer);
    247248
    248     virtual void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
     249    virtual void ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers);
     250    virtual void ShowPIP(VideoFrame        *frame,
     251                         NuppelVideoPlayer *pipplayer,
     252                         PIPLocation        loc);
     253
    249254    virtual int DisplayOSD(VideoFrame *frame, OSD *osd, int stride = -1, int revision = -1);
    250255
    251256    virtual void SetPictureAttributeDBValue(
     
    288293    unsigned char      *pip_tmp_buf;
    289294    unsigned char      *pip_tmp_buf2;
    290295    ImgReSampleContext *pip_scaling_context;
    291     bool pad_pip_window;
    292296    VideoFrame pip_tmp_image;
    293297
    294298    // Video resizing (for ITV)
  • libs/libmythtv/videoout_ivtv.cpp

     
    693693{
    694694}
    695695
    696 void VideoOutputIvtv::ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
     696void VideoOutputIvtv::ShowPIP(VideoFrame        *frame,
     697                              NuppelVideoPlayer *pipplayer,
     698                              PIPLocation        loc)
    697699{
    698700    if (!pipplayer)
    699701        return;
     
    738740        }
    739741    }
    740742
    741     switch (windows[0].GetPIPLocation())
     743    switch (loc)
    742744    {
    743745        case kPIP_END:
    744746        case kPIPTopLeft:
     
    782784
    783785void VideoOutputIvtv::ProcessFrame(VideoFrame *frame, OSD *osd,
    784786                                   FilterChain *filterList,
    785                                    NuppelVideoPlayer *pipPlayer)
     787                                   const PIPMap &pipPlayers)
    786788{
    787789    (void)filterList;
    788790    (void)frame;
     
    813815        surface = osd->Display();
    814816
    815817    // Clear osdbuf if OSD has changed, or PiP has been toggled
    816     bool clear = (pipPlayer!=0) ^ pipon;
     818    bool clear = (!pipPlayers.empty()) ^ pipon;
    817819    int new_revision = osdbuf_revision;
    818820    if (surface)
    819821    {
     
    828830        drawanyway = true;
    829831    }
    830832
    831     if (pipPlayer)
     833    if (!pipPlayers.empty())
    832834    {
    833         ShowPIP(&tmpframe, pipPlayer);
     835        ShowPIPs(&tmpframe, pipPlayers);
    834836        osdbuf_revision = 0xfffffff; // make sure OSD is redrawn
    835837        lastcleared = false;
    836838        drawanyway  = true;
     
    849851        {
    850852            bzero(tmpframe.buf, video_dim.height() * stride);
    851853            // redraw PiP...
    852             if (pipPlayer)
    853                 ShowPIP(&tmpframe, pipPlayer);
     854            if (!pipPlayers.empty())
     855                ShowPIPs(&tmpframe, pipPlayers);
    854856        }
    855857        drawanyway  |= !lastcleared || pipon;
    856858        lastcleared &= !pipon;
     
    858860
    859861    // Set these so we know if/how to clear if need be, the next time around.
    860862    osdon = (ret >= 0);
    861     pipon = (bool) pipPlayer;
     863    pipon = (bool) !pipPlayers.empty();
    862864
    863865    // If there is an OSD, make sure we draw OSD surface
    864866    lastcleared &= !osdon;
  • libs/libmythtv/videoout_null.h

     
    3737    void UpdatePauseFrame(void);
    3838    void ProcessFrame(VideoFrame *frame, OSD *osd,
    3939                      FilterChain *filterList,
    40                       NuppelVideoPlayer *pipPlayer);
     40                      const PIPMap &pipPlayers);
    4141
    4242    static QStringList GetAllowedRenderers(MythCodecID myth_codec_id,
    4343                                           const QSize &video_dim);