Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 19373)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -214,8 +214,8 @@
       audio_channels(2),            audio_bits(-1),
       audio_samplerate(44100),      audio_stretchfactor(1.0f),
       audio_codec(NULL),
-      // Picture-in-Picture
-      pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false),
+      // Picture-in-Picture stuff
+      pip_active(false),
       // Preview window support
       argb_buf(NULL),               argb_size(0,0),
       yuv2argb_conv(yuv2rgb_init_mmx(32, MODE_RGB)),
@@ -1152,6 +1152,9 @@
     SetDecoder(dec);
 }
 
+extern "C" {
+#include "libavutil/crc.h"
+}
 int NuppelVideoPlayer::OpenFile(bool skipDsp, uint retries,
                                 bool allow_libmpeg2)
 {
@@ -1189,6 +1192,16 @@
             return -1;
         }
 
+        long long pos = player_ctx->buffer->Seek(0, SEEK_CUR);
+        uint checksum = av_crc(av_crc_get_table(AV_CRC_32_IEEE),
+                               (uint32_t) -1,
+                               (uint8_t*)testbuf, testreadsize - 1);
+        VERBOSE(VB_PLAYBACK, LOC +
+                QString("Looking for decoder for '%1'@%2 "
+                        "probe size %3 crc 0x%4")
+                .arg(player_ctx->buffer->GetFilename())
+                .arg(pos).arg(testreadsize).arg(checksum,0,16));
+
         player_ctx->LockPlayingInfo(__FILE__, __LINE__);
         if (NuppelDecoder::CanHandle(testbuf, testreadsize))
             SetDecoder(new NuppelDecoder(this, *player_ctx->playingInfo));
@@ -2468,12 +2481,12 @@
                     player_ctx->buffer->DVD()->InStillFrame() &&
                     videoOutput->ValidVideoFrames() < 3)
                 {
-                    videoOutput->ProcessFrame(buffer, NULL, NULL, pipplayer);
+                    videoOutput->ProcessFrame(buffer, NULL, NULL, pip_players);
                 }
                 else
                 {
                     videoOutput->ProcessFrame(
-                        buffer, osd, videoFilters, pipplayer);
+                        buffer, osd, videoFilters, pip_players);
                 }
                 videofiltersLock.unlock();
             }
@@ -2633,7 +2646,7 @@
     DisplayDVDButton();
 
     videofiltersLock.lock();
-    videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
+    videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
     videofiltersLock.unlock();
 
     videoOutput->PrepareFrame(NULL, kScan_Ignore);
@@ -2858,10 +2871,12 @@
         player_ctx->buffer->DVD()->InStillFrame() &&
         videoOutput->ValidVideoFrames() < 3)
     {
-        videoOutput->ProcessFrame(frame, NULL, NULL, pipplayer);
+        videoOutput->ProcessFrame(frame, NULL, NULL, pip_players);
     }
     else
-        videoOutput->ProcessFrame(frame, osd, videoFilters, pipplayer);
+    {
+        videoOutput->ProcessFrame(frame, osd, videoFilters, pip_players);
+    }
     videofiltersLock.unlock();
 
     if (audioOutput && !audio_paused && audioOutput->IsPaused())
@@ -2954,16 +2969,7 @@
 
     while (!killvideo)
     {
-        if (needsetpipplayer)
-        {
-            pipplayer = setpipplayer;
-            needsetpipplayer = false;
-            PIPState state = player_ctx->GetPIPState();
-            if (m_tv && (state == kPIPOff  || state == kPBPLeft))
-                m_tv->WakeSetPIPPlayerCond();
-            if (videoOutput)
-                videoOutput->PadPIPImage(false);
-        }
+        HandlePIPPlayerLists(4);
 
         if (player_ctx->buffer->isDVD())
         {
@@ -3046,11 +3052,7 @@
 
     while (!killvideo)
     {
-        if (needsetpipplayer)
-        {
-            pipplayer = setpipplayer;
-            needsetpipplayer = false;
-        }
+        HandlePIPPlayerLists(1);
 
         resetvideo = false;
         SetVideoActuallyPaused(pausevideo);
@@ -3058,7 +3060,7 @@
         if (pausevideo)
         {
             videofiltersLock.lock();
-            videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
+            videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
             videofiltersLock.unlock();
         }
         else
@@ -3068,7 +3070,7 @@
                 ShowText();
 
             videofiltersLock.lock();
-            videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
+            videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
             videofiltersLock.unlock();
         }
 
@@ -3250,10 +3252,10 @@
     }
     else
     {
+        if (player_ctx)
+            player_ctx->SetNVPChangingBuffers(true);
         GetDecoder()->SetReadAdjust(player_ctx->buffer->SetAdjustFilesize());
         GetDecoder()->SetWaitForChange();
-        if (m_tv && player_ctx && !player_ctx->isPIP())
-            m_tv->SetIgnoreKeys(true);
     }
 
     delete pginfo;
@@ -3293,8 +3295,7 @@
 
     player_ctx->buffer->Unpause();
 
-    if (m_tv && player_ctx && !player_ctx->isPIP())
-        m_tv->SetIgnoreKeys(false);
+    player_ctx->SetNVPChangingBuffers(false);
 
     player_ctx->LockPlayingInfo(__FILE__, __LINE__);
     player_ctx->tvchain->SetProgram(*player_ctx->playingInfo);
@@ -3867,6 +3868,106 @@
         GetDecoder()->setTranscoding(value);
 };
 
+bool NuppelVideoPlayer::AddPIPPlayer(
+    NuppelVideoPlayer *pip, PIPLocation loc, uint timeout)
+{
+    QMutexLocker locker(&pip_players_lock);
+    pip_players_add[pip] = loc;
+
+    pip_players_wait.wait(&pip_players_lock, timeout);
+
+    if (pip_players.find(pip) != pip_players.end())
+        return true;
+
+    PIPMap::iterator it = pip_players_add.find(pip);
+    if (it != pip_players_add.end())
+        pip_players_add.erase(it);
+
+    return false;
+}
+
+bool NuppelVideoPlayer::RemovePIPPlayer(NuppelVideoPlayer *pip, uint timeout)
+{
+    QMutexLocker locker(&pip_players_lock);
+
+    pip_players_rm[pip] = kPIP_END;
+
+    pip_players_wait.wait(&pip_players_lock, timeout);
+
+    if (pip_players.find(pip) == pip_players.end())
+        return true;
+
+    PIPMap::iterator it = pip_players_rm.find(pip);
+    if (it != pip_players_rm.end())
+        pip_players_rm.erase(it);
+
+    return false;
+}
+
+void NuppelVideoPlayer::HandlePIPPlayerLists(uint max_cnt)
+{
+    QMutexLocker locker(&pip_players_lock);
+    PIPMap::const_iterator it = pip_players_rm.begin();
+    for (; it != pip_players_rm.end(); ++it)
+    {
+        PIPMap::iterator it2 = pip_players.find(it.key());
+        if (it2 != pip_players.end())
+            pip_players.erase(it2);
+    }
+
+    for (it = pip_players_add.begin();
+         (it != pip_players_add.end()) &&
+         ((uint)pip_players.size() <= max_cnt); ++it)
+    {
+        if (pip_players.find(it.key())    == pip_players.end() &&
+            pip_players_rm.find(it.key()) == pip_players_rm.end())
+        {
+            pip_players[it.key()] = *it;
+        }
+    }
+    pip_players_add.clear();
+    pip_players_rm.clear();
+    pip_players_wait.wakeAll();
+}
+
+PIPLocation NuppelVideoPlayer::GetNextPIPLocation(void) const
+{
+    QMutexLocker locker(&pip_players_lock);
+    PIPMap sim_pip_players = pip_players;
+
+    PIPMap::const_iterator it = pip_players_rm.begin();
+    for (; it != pip_players_rm.end(); ++it)
+    {
+        PIPMap::iterator it2 = sim_pip_players.find(it.key());
+        if (it2 != sim_pip_players.end())
+            sim_pip_players.erase(it2);
+    }
+
+    for (it = pip_players_add.begin(); it != pip_players_add.end(); ++it)
+    {
+        if (sim_pip_players.find(it.key()) == sim_pip_players.end() &&
+            pip_players_rm.find(it.key())  == pip_players_rm.end())
+        {
+            sim_pip_players[it.key()] = *it;
+        }
+    }
+
+    // order of preference, could be stored in db if we want it configurable
+    PIPLocation ols[] =
+        { kPIPTopLeft, kPIPTopRight, kPIPBottomLeft, kPIPBottomRight };
+
+    for (uint i = 0; i < sizeof(ols)/sizeof(PIPLocation); i++)
+    {
+        PIPMap::const_iterator it = sim_pip_players.begin();
+        for (; it != sim_pip_players.end() && (*it != ols[i]); ++it);
+
+        if (it == sim_pip_players.end())
+            return ols[i];
+    }
+
+    return kPIP_END;
+}
+
 void NuppelVideoPlayer::WrapTimecode(long long &timecode, TCTypes tc_type) 
 {
     if ((tc_type == TC_AUDIO) && (tc_wrap[TC_AUDIO] == LONG_LONG_MIN))
Index: libs/libmythtv/videooutwindow.cpp
===================================================================
--- libs/libmythtv/videooutwindow.cpp	(revision 19373)
+++ libs/libmythtv/videooutwindow.cpp	(working copy)
@@ -54,7 +54,7 @@
 VideoOutWindow::VideoOutWindow() :
     // DB settings
     db_move(0, 0), db_scale_horiz(0.0f), db_scale_vert(0.0f),
-    db_pip_location(kPIPTopLeft), db_pip_size(26),
+    db_pip_size(26),
     db_scaling_allowed(true),
 
     // Manual Zoom
@@ -82,9 +82,6 @@
     embedding(false), needrepaint(false),
     allowpreviewepg(true), pip_state(kPIPOff)
 {
-    db_pip_location = (PIPLocation) gContext->GetNumSetting(
-        "PIPLocation", (int) kPIPTopLeft);
-
     db_pip_size = gContext->GetNumSetting("PIPSize", 26);
 
     db_move = QPoint(gContext->GetNumSetting("xScanDisplacement", 0),
@@ -732,7 +729,7 @@
  * \brief Determines PIP Window size and Position.
  */
 QRect VideoOutWindow::GetPIPRect(
-    int location, NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
+    PIPLocation location, NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
 {
     QRect position;
 
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 19373)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -873,6 +873,9 @@
  *  \param novideo if true then no video is sought in ScanSreams.
  *  \param testbuf this parameter is not used by AvFormatDecoder.
  */
+extern "C" {
+#include "libavutil/crc.h"
+}
 int AvFormatDecoder::OpenFile(RingBuffer *rbuffer, bool novideo, 
                               char testbuf[kDecoderProbeBufferSize],
                               int testbufsize)
@@ -899,12 +902,19 @@
         probe.buf_size = kDecoderProbeBufferSize - AVPROBE_PADDING_SIZE;
 
     fmt = av_probe_input_format(&probe, true);
+    uint checksum = av_crc(av_crc_get_table(AV_CRC_32_IEEE),
+                           (uint32_t) -1,
+                           (uint8_t*)testbuf, probe.buf_size - 1);
     if (!fmt)
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR +
-                QString("Probe failed for file: \"%1\".").arg(filename));
+                QString("Probe failed for file: '%1' probe size %2 crc 0x%3")
+                .arg(filename).arg(probe.buf_size).arg(checksum,0,16));
         return -1;
     }
+    VERBOSE(VB_IMPORTANT, LOC +
+            QString("Probe suceeded for file: '%1' probe size %2 crc 0x%3")
+            .arg(filename).arg(probe.buf_size).arg(checksum,0,16));
 
     fmt->flags |= AVFMT_NOFILE;
 
Index: libs/libmythtv/tv_play.h
===================================================================
--- libs/libmythtv/tv_play.h	(revision 19373)
+++ libs/libmythtv/tv_play.h	(working copy)
@@ -150,9 +150,6 @@
 
     // LiveTV commands
     bool LiveTV(bool showDialogs = true, bool startInGuide = false);
-    /// This command is used to exit the player in order to record using
-    /// the recording being used by LiveTV.
-    void StopLiveTV(void) { SetExitPlayer(true, true); }
 
     // Embedding commands for the guidegrid to use in LiveTV
     void EmbedOutput(PlayerContext*, WId wid, int x, int y, int w, int h);
@@ -184,9 +181,9 @@
     bool IsBookmarkAllowed(const PlayerContext*) const;
     bool IsDeleteAllowed(const PlayerContext*) const;
 
-    bool CreatePBP(PlayerContext*, const ProgramInfo *info);
-    bool CreatePIP(PlayerContext*, const ProgramInfo *info);
-    void ResizePIPWindow(PlayerContext*);
+    bool CreatePBP(PlayerContext *lctx, const ProgramInfo *info);
+    bool CreatePIP(PlayerContext *lctx, const ProgramInfo *info);
+    bool ResizePIPWindow(PlayerContext*);
     bool IsPIPSupported(const PlayerContext *ctx = NULL) const;
 
     // Boolean queries
@@ -238,14 +235,11 @@
                         bool inPlaylist = false, bool initByNetworkCommand = false);
     static void SetFuncPtr(const char *, void *);
 
-    void SetIgnoreKeys(bool ignore) { ignoreKeys = ignore; }
-
     // Used by EPG
     void ChangeVolume(PlayerContext*, bool up);
     void ToggleMute(PlayerContext*);
 
-    void WakeSetPIPPlayerCond(void);
-    void SetNextProgPIPState(PIPState state) { nextProgPIPState = state; }
+    void SetNextProgPIPState(PIPState state) { jumpToProgramPIPState = state; }
 
     // Used for UDPNotify
     bool HasUDPNotifyEvent(void) const;
@@ -276,7 +270,7 @@
     static EMBEDRETURNVOID RunViewScheduledPtr;
 
   private:
-    void SetActive(PlayerContext *, int index);
+    void SetActive(PlayerContext *lctx, int index, bool osd_msg);
 
     PlayerContext       *GetPlayerWriteLock(
         int which, const char *file, int location);
@@ -297,18 +291,20 @@
 
     int  StartTimer(int interval, int line);
     void KillTimer(int id);
-    void ForceNextStateNone(PlayerContext*);
+    void ForceNextStateNone(PlayerContext*, int line);
     void ScheduleStateChange(PlayerContext*);
     void SetErrored(PlayerContext*);
-    void SetExitPlayer(bool set_it, bool wants_to) const;
+    void SetExitPlayerReal(bool set_it, bool wants_to, int line) const;
     void SetUpdateOSDPosition(bool set_it);
 
-    bool PIPHandleAction(PlayerContext*,const QStringList &actions);
+    bool PxPHandleAction(PlayerContext*,const QStringList &actions);
     bool ToggleHandleAction(PlayerContext*,
                             const QStringList &actions, bool isDVD);
     bool FFRewHandleAction(PlayerContext*, const QStringList &actions);
     bool ActivePostQHandleAction(PlayerContext*,
                                  const QStringList &actions, bool isDVD);
+    bool HandleJumpToProgramAction(PlayerContext *ctx,
+                                   const QStringList   &actions);
 
     bool RequestNextRecorder(PlayerContext *, bool);
     void DeleteRecorder();
@@ -422,7 +418,6 @@
                                 const QStringList &actions);
 
     void DoDisplayJumpMenu(void);
-    void SetJumpToProgram(QString progKey = "", int progIndex = 0);
  
     bool ClearOSD(const PlayerContext*);
     void ToggleOSD(const PlayerContext*, bool includeStatusOSD); 
@@ -442,23 +437,28 @@
                       int editType = kScheduleProgramGuide);
 
     void TeardownPlayer(PlayerContext *mctx, PlayerContext *ctx);
-    void TeardownPBP(PlayerContext*);
 
     void HandleStateChange(PlayerContext *mctx, PlayerContext *ctx);
 
     bool StartPlayer(PlayerContext *mctx, PlayerContext *ctx,
-                     TVState desiredState, bool ispip = false);
-    bool StartPIPPlayer(PlayerContext *mctx, PlayerContext *pipctx,
-                        TVState desiredState);
-    void SetPIPPlayer(PlayerContext *mctx, PlayerContext *pipctx);
-    void TogglePIPView(PlayerContext*, bool ispbp = false);
-    void ToggleActiveWindow(PlayerContext*, int ctx_index);
-    void SwapPIP(PlayerContext *lctx, int ctx_index, bool ispbp);
-    void TogglePIPState(PlayerContext*, PIPState changeTo);
-    void RestartPIPWindows(PlayerContext *lctx, const vector<long long> &pos,
-                           MuteState mctx_mute);
-    void TeardownPIPWindows(PlayerContext*);
+                     TVState desiredState);
 
+    vector<long long> TeardownAllNVPs(PlayerContext*);
+    void RestartAllNVPs(PlayerContext *lctx,
+                        const vector<long long> &pos,
+                        MuteState mctx_mute);
+
+    void PxPToggleView(  PlayerContext *actx, bool wantPBP);
+    void PxPCreateView(  PlayerContext *actx, bool wantPBP);
+    void PxPTeardownView(PlayerContext *actx);
+    void PxPToggleType(  PlayerContext *mctx, bool wantPBP);
+    void PxPSwap(        PlayerContext *mctx, int ctx_index = -1);
+    bool HandlePxPTimerEvent(void);
+
+    bool PIPAddPlayer(   PlayerContext *mctx, PlayerContext *ctx);
+    bool PIPRemovePlayer(PlayerContext *mctx, PlayerContext *ctx);
+    void PBPRestartMainNVP(PlayerContext *mctx);
+
     void ToggleAutoExpire(PlayerContext*);
 
     void BrowseStart(PlayerContext*);
@@ -479,6 +479,8 @@
 
     void BuildOSDTreeMenu(const PlayerContext*);
     void ShowOSDTreeMenu(const PlayerContext*);
+    void FillMenuPxP(const PlayerContext*, OSDGenericTree *treeMenu,
+                     bool freeRecorders);
     void FillMenuLiveTV(OSDGenericTree *treeMenu);
     void FillMenuPlaying(const PlayerContext*, OSDGenericTree *treeMenu);
 
@@ -509,8 +511,8 @@
     void IdleDialogTimeout(void);
 
     // Program jumping stuff
-    void setLastProgram(ProgramInfo *rcinfo);
-    ProgramInfo *getLastProgram(void) { return lastProgram; }
+    void SetLastProgram(ProgramInfo *rcinfo);
+    ProgramInfo *GetLastProgram(void) const;
 
     static bool LoadExternalSubtitles(NuppelVideoPlayer *nvp,
                                       const QString &videoFile);
@@ -537,8 +539,20 @@
     QString db_time_format;
     QString db_short_date_format;
     uint    db_idle_timeout;
+    uint    db_udpnotify_port;
+    int     db_playback_exit_prompt;
+    int     db_autoexpire_default;
     bool    db_auto_set_watched;
     bool    db_end_of_rec_exit_prompt;
+    bool    db_jump_prefer_osd;
+    bool    db_use_gui_size_for_tv;
+    bool    db_start_in_guide;
+    bool    db_toggle_bookmark;
+    bool    db_run_jobs_on_remote;
+    bool    db_use_dvd_bookmark;
+    bool    db_continue_embedded;
+    bool    db_use_fixed_size;
+
     bool    smartChannelChange;
     bool    MuteIndividualChannels;
     bool    arrowAccel;
@@ -582,9 +596,8 @@
     QMap<QString,AskProgramInfo> askAllowPrograms;
     QMutex                       askAllowLock;
 
-    bool ignoreKeys;
-    PIPState needToMakePIPChange;
-    PIPState nextProgPIPState;
+    MythDeque<QString> changePxP;
+    QMutex progListsLock;
     QMap<QString,ProgramList> progLists;
 
     mutable QMutex chanEditMapLock; ///< Lock for chanEditMap and ddMap
@@ -639,20 +652,22 @@
 
     // Program Info for currently playing video
     // (or next video if InChangeState() is true)
+    mutable QMutex lastProgramLock;
     ProgramInfo *lastProgram;   ///< last program played with this player
-    bool         jumpToProgram;
-
     bool         inPlaylist; ///< show is part of a playlist
     bool         underNetworkControl; ///< initial show started via by the network control interface
     bool         isnearend;
 
+    // Program Jumping
+    PIPState     jumpToProgramPIPState;
+    bool         jumpToProgram;
+
     // Video Players
     vector<PlayerContext*>  player;
     /// Video Player to which events are sent to
     int                     playerActive;
     /// lock on player and playerActive changes
     mutable QReadWriteLock  playerLock;
-    QWaitCondition pipPlayerSetCondition;
 
     // Remote Encoders
     /// Main recorder to use after a successful SwitchCards() call.
@@ -741,6 +756,8 @@
     static const uint kInputKeysMax; ///< When to start discarding early keys
     static const uint kNextSource;
     static const uint kPreviousSource;
+    static const uint kMaxPIPCount;
+    static const uint kMaxPBPCount;
 
     ///< Timeout for entry modes in msec
     static const uint kInputModeTimeout;
Index: libs/libmythtv/videoout_ivtv.h
===================================================================
--- libs/libmythtv/videoout_ivtv.h	(revision 19373)
+++ libs/libmythtv/videoout_ivtv.h	(working copy)
@@ -32,7 +32,7 @@
     void UpdatePauseFrame(void);
     void ProcessFrame(VideoFrame *frame, OSD *osd,
                       FilterChain *filterList,
-                      NuppelVideoPlayer *pipPlayer);
+                      const PIPMap &pipPlayers);
 
     uint WriteBuffer(unsigned char *buf, int count);
     int Poll(int delay);
@@ -77,7 +77,7 @@
         kAlpha_Embedded
     } eAlphaState;
 
-    void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
+    void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer, PIPLocation);
     void SetAlpha(eAlphaState newAlpha);
     void SetColorKey(int state, int color);
     long long GetFirmwareFramesPlayed(void);
Index: libs/libmythtv/playercontext.cpp
===================================================================
--- libs/libmythtv/playercontext.cpp	(revision 19373)
+++ libs/libmythtv/playercontext.cpp	(working copy)
@@ -30,7 +30,7 @@
 }
 
 PlayerContext::PlayerContext() :
-    nvp(NULL), recorder(NULL),
+    nvp(NULL), nvpUnsafe(false), recorder(NULL),
     tvchain(NULL), buffer(NULL), playingInfo(NULL),
     decoding(false), last_cardid(-1), last_framerate(30.0f),
     // Fast forward state
@@ -102,7 +102,7 @@
         newPlaygroup = playingInfo->playgroup;
     }
 
-    ChangeState(newState);
+    ChangeState(newState, __LINE__);
     SetPlayGroup(newPlaygroup);
 }
 
@@ -141,8 +141,7 @@
     if (pos > -1)
     {
         pipLocation = pos;
-        name = QString("pip player %1")
-                .arg(PIPLocationToString());
+        name = QString("pip player %1").arg(toString((PIPLocation)pos));
     }
     else
         name = "pip player";
@@ -216,65 +215,6 @@
     }
 }
 
-QString PlayerContext::PIPLocationToString(void)
-{
-    QString pipstr = QString ("Unknown PIP Location %1").arg(pipLocation);
-    switch (pipLocation)
-    {
-        case (kPIPTopLeft):
-            pipstr = "PIP: Top Left";
-            break;
-        case (kPIPTopRight):
-            pipstr = "PIP: Top Right";
-            break;
-        case (kPIPBottomLeft):
-            pipstr = "PIP: Bottom Left";
-            break;
-        case (kPIPBottomRight):
-            pipstr = "PIP: Bottom Right";
-            break;
-    }
-
-    return pipstr;
-}
-
-QString PlayerContext::PIPStateToString(void)
-{
-    QString pipstr = QString("Unknown PIP State %1").arg(pipState);
-    switch (pipState)
-    {
-        case (kPIPOff):
-            pipstr = "PIP is off";
-            break;
-        case (kPIPonTV):
-            pipstr = "PIP is visible on TV";
-            break;
-        case (kPIPStandAlone):
-            pipstr = "Standalone PIP";
-            break;
-        case (kPBPLeft):
-            pipstr = "Left side Picture-by-Picture";
-            break;
-        case (kPBPRight):
-            pipstr = "Right side Picture-by-Picture";
-            break;
-        case (kPIPToPBP):
-            pipstr = "Preparing to switch from PIP to PBP";
-            break;
-        case (kPBPToPIP):
-            pipstr = "Preparing to switch from PBP to PIP";
-            break;
-        case (kPBPToggle):
-            pipstr = "Disabling PBP/PIP";
-            break;
-        case (kPIPSwap):
-            pipstr = "Swapping PBP/PIP";
-            break;
-    }
-
-    return pipstr;
-}
-
 bool PlayerContext::StartPIPPlayer(TV *tv, TVState desiredState)
 {
     bool ok = false;
@@ -440,8 +380,8 @@
         nvp->SetMuted(true);
 
     int maxWait = -1;
-    if (isPIP())
-       maxWait = 1000; 
+    //if (isPIP())
+    //   maxWait = 1000; 
 
     return StartDecoderThread(maxWait);
 }
@@ -649,8 +589,10 @@
 /**
 *   \brief Puts a state change on the nextState queue.
 */
-void PlayerContext::ChangeState(TVState newState)
+void PlayerContext::ChangeState(TVState newState, int line)
 {
+    VERBOSE(VB_IMPORTANT, QString("ChangeState(%1,%2)")
+            .arg(StateToString(newState)).arg(line));
     QMutexLocker locker(&stateLock);
     nextState.enqueue(newState);
 }
@@ -664,8 +606,9 @@
 /**
  * \brief Removes any pending state changes, and puts kState_None on the queue.
  */
-void PlayerContext::ForceNextStateNone(void)
+void PlayerContext::ForceNextStateNone(int line)
 {
+    VERBOSE(VB_IMPORTANT, QString("ForceNextStateNone(%2)").arg(line));
     QMutexLocker locker(&stateLock);
     nextState.clear();
     nextState.push_back(kState_None);
Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 19373)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -149,8 +149,9 @@
     void SetVideoFilters(const QString &override);
     void SetFramesPlayed(long long played)    { framesPlayed = played; }
     void SetEof(void)                         { eof = true; }
-    void SetPIPPlayer(NuppelVideoPlayer *pip)
-        { setpipplayer = pip; needsetpipplayer = true; }
+    void SetPIPActive(bool is_active)         { pip_active = is_active; }
+    bool AddPIPPlayer(NuppelVideoPlayer *pip, PIPLocation loc, uint timeout);
+    bool RemovePIPPlayer(NuppelVideoPlayer *pip, uint timeout);
 
     void SetTranscoding(bool value);
     void SetWatchingRecording(bool mode);
@@ -203,12 +204,12 @@
     QString   GetXDS(const QString &key) const;
     QString   GetErrorMsg(void) const { return errmsg; }
     bool      GetAudioBufferStatus(uint &fill, uint &total) const;
+    PIPLocation GetNextPIPLocation(void) const;
 
     // Bool Gets
     bool    GetRawAudioState(void) const;
     bool    GetLimitKeyRepeat(void) const     { return limitKeyRepeat; }
     bool    GetEof(void) const                { return eof; }
-    bool    PipPlayerSet(void) const          { return !needsetpipplayer; }
     bool    IsErrored(void) const             { return errored; }
     bool    IsPlaying(uint wait_ms = 0, bool wait_for = true) const;
     bool    AtNormalSpeed(void) const         { return next_normal_speed; }
@@ -218,6 +219,7 @@
     bool    PlayingSlowForPrebuffer(void) const { return m_playing_slower; }
     bool    HasAudioIn(void) const            { return !no_audio_in; }
     bool    HasAudioOut(void) const           { return !no_audio_out; }
+    bool    IsPIPActive(void) const           { return pip_active; }
     bool    IsMuted(void) const        { return GetMuteState() == kMuteAll; }
     bool    IsIVTVDecoder(void) const;
     bool    UsingNullVideo(void) const { return using_null_videoout; }
@@ -530,6 +532,9 @@
     long long GetDVDBookmark(void) const;
     void SetDVDBookmark(long long frames);
 
+    // Private PIP stuff
+    void HandlePIPPlayerLists(uint max_pip_players);
+
   private:
     DecoderBase   *decoder;
     QMutex         decoder_change_lock;
@@ -702,9 +707,12 @@
     bool     audio_passthru;
 
     // Picture-in-Picture
-    NuppelVideoPlayer *pipplayer;
-    NuppelVideoPlayer *setpipplayer;
-    bool needsetpipplayer;
+    mutable QMutex pip_players_lock;
+    QWaitCondition pip_players_wait;
+    PIPMap         pip_players;
+    PIPMap         pip_players_add;
+    PIPMap         pip_players_rm;
+    volatile bool  pip_active;
 
     // Preview window support
     unsigned char      *argb_buf;
Index: libs/libmythtv/tv_play.cpp
===================================================================
--- libs/libmythtv/tv_play.cpp	(revision 19373)
+++ libs/libmythtv/tv_play.cpp	(working copy)
@@ -65,12 +65,16 @@
 
 #define GetPlayer(X,Y) GetPlayerHaveLock(X, Y, __FILE__ , __LINE__)
 #define GetOSDLock(X) GetOSDL(X, __FILE__, __LINE__)
+#define SetExitPlayer(X,Y) SetExitPlayerReal(X,Y,__LINE__)
 
 const int  TV::kInitFFRWSpeed                = 0;
 const uint TV::kInputKeysMax                 = 6;
 const uint TV::kNextSource                   = 1;
 const uint TV::kPreviousSource               = 2;
+const uint TV::kMaxPIPCount                  = 4;
+const uint TV::kMaxPBPCount                  = 2;
 
+
 const uint TV::kInputModeTimeout             = 5000;
 const uint TV::kMuteTimeout                  = 800;
 const uint TV::kLCDTimeout                   = 1000;
@@ -154,8 +158,8 @@
     if (!lastProgramStringList.empty())
     {
         ProgramInfo *p = new ProgramInfo();
-        p->FromStringList(lastProgramStringList, 0);
-        tv->setLastProgram(p);
+        if (p->FromStringList(lastProgramStringList, 0))
+            tv->SetLastProgram(p);
         delete p;
     }
 
@@ -175,7 +179,7 @@
             VERBOSE(VB_PLAYBACK, LOC + "tv->LiveTV() -- begin");
             if (!tv->LiveTV(showDialogs, startInGuide))
             {
-                tv->StopLiveTV();
+                tv->SetExitPlayerReal(true, true, __LINE__);
                 quitAll = true;
             }
             VERBOSE(VB_PLAYBACK, LOC + "tv->LiveTV() -- end");
@@ -270,17 +274,11 @@
 
         if (tv->getJumpToProgram())
         {
+            ProgramInfo *nextProgram = tv->GetLastProgram();
 
-            ProgramInfo *tmpProgram  = tv->getLastProgram();
-            ProgramInfo *nextProgram = new ProgramInfo(*tmpProgram);
-
+            tv->SetLastProgram(curProgram);
             if (curProgram)
-            {
-                tv->setLastProgram(curProgram);
                 delete curProgram;
-            }
-            else
-                tv->setLastProgram(NULL);
 
             curProgram = nextProgram;
 
@@ -420,14 +418,17 @@
     REG_KEY("TV Playback", "VOLUMEDOWN", "Volume down", "[,{,F10,Volume Down");
     REG_KEY("TV Playback", "VOLUMEUP",   "Volume up",   "],},F11,Volume Up");
     REG_KEY("TV Playback", "MUTE",       "Mute",        "|,\\,F9,Volume Mute");
-    REG_KEY("TV Playback", "TOGGLEPIPMODE", "Toggle Picture-in-Picture mode",
+    REG_KEY("TV Playback", "TOGGLEPIPMODE", "Toggle Picture-in-Picture view",
             "V");
-    REG_KEY("TV Playback", "TOGGLEPBPMODE", "Toggle Picture-by-Picture mode",
+    REG_KEY("TV Playback", "TOGGLEPBPMODE", "Toggle Picture-by-Picture view",
             "Ctrl+V");
-    REG_KEY("TV Playback", "TOGGLEPIPWINDOW", "Toggle active PIP/PBP window", "B");
+    REG_KEY("TV Playback", "CREATEPIPVIEW", "Create Picture-in-Picture view",
+            "1");
+    REG_KEY("TV Playback", "CREATEPBPVIEW", "Create Picture-by-Picture view",
+            "Ctrl+1");
+    REG_KEY("TV Playback", "NEXTPIPWINDOW", "Toggle active PIP/PBP window", "B");
     REG_KEY("TV Playback", "SWAPPIP", "Swap PBP/PIP Windows", "N");
-    REG_KEY("TV Playback", "TOGGLEPIPSTATE", "Change PIP from PBP or visa versa"
-            ,"");
+    REG_KEY("TV Playback", "TOGGLEPIPSTATE", "Change PxP view", "");
     REG_KEY("TV Playback", "TOGGLEASPECT",
             "Toggle the video aspect ratio", "Ctrl+W");
     REG_KEY("TV Playback", "TOGGLEFILL", "Next Preconfigured Zoom mode", "W");
@@ -569,9 +570,14 @@
       baseFilters(""),
       db_channel_format("<num> <sign>"),
       db_time_format("h:mm AP"), db_short_date_format("M/d"),
-      db_idle_timeout(0),
-      db_auto_set_watched(false),
-      db_end_of_rec_exit_prompt(false),
+      db_idle_timeout(0),           db_udpnotify_port(0),
+      db_playback_exit_prompt(0),   db_autoexpire_default(0),
+      db_auto_set_watched(false),   db_end_of_rec_exit_prompt(false),
+      db_jump_prefer_osd(true),     db_use_gui_size_for_tv(false),
+      db_start_in_guide(false),     db_toggle_bookmark(false),
+      db_run_jobs_on_remote(false), db_use_dvd_bookmark(false),
+      db_continue_embedded(false),  db_use_fixed_size(true),
+
       smartChannelChange(false),
       MuteIndividualChannels(false), arrowAccel(false),
       osd_general_timeout(2), osd_prog_info_timeout(3),
@@ -594,9 +600,6 @@
       adjustingPicture(kAdjustingPicture_None),
       adjustingPictureAttribute(kPictureAttribute_None),
       askAllowType(kAskAllowCancel), askAllowLock(QMutex::Recursive),
-      ignoreKeys(false),
-      needToMakePIPChange(kPIPOff),
-      nextProgPIPState(kPIPOff),
       // Channel Editing
       chanEditMapLock(QMutex::Recursive),
       ddMapSourceId(0), ddMapLoaderRunning(false),
@@ -615,9 +618,12 @@
       browsemode(false), persistentbrowsemode(false),
       browsechannum(""), browsechanid(""), browsestarttime(""),
       // Program Info for currently playing video
-      lastProgram(NULL), jumpToProgram(false),
+      lastProgram(NULL),
       inPlaylist(false), underNetworkControl(false),
       isnearend(false),
+      // Jump to program stuff
+      jumpToProgramPIPState(kPIPOff),
+      jumpToProgram(false),
       // Video Player currently receiving UI input
       playerActive(-1),
       //Recorder switching info
@@ -647,9 +653,23 @@
 
     db_idle_timeout = gContext->GetNumSetting("LiveTVIdleTimeout", 0);
     db_idle_timeout *= 60 * 1000; // convert from minutes to ms.
-    db_auto_set_watched = gContext->GetNumSetting("AutomaticSetWatched", 0);
+    db_udpnotify_port      = gContext->GetNumSetting("UDPNotifyPort", 0);
+    db_playback_exit_prompt= gContext->GetNumSetting("PlaybackExitPrompt", 0);
+    db_autoexpire_default  = gContext->GetNumSetting("AutoExpireDefault", 0);
+
+    db_auto_set_watched     = gContext->GetNumSetting("AutomaticSetWatched", 0);
     db_end_of_rec_exit_prompt =
         gContext->GetNumSetting("EndOfRecordingExitPrompt", 0);
+    db_jump_prefer_osd     = gContext->GetNumSetting("JumpToProgramOSD", 1);
+    db_use_gui_size_for_tv = gContext->GetNumSetting("GuiSizeForTV", 0);
+    db_start_in_guide      = gContext->GetNumSetting("WatchTVGuide", 0);
+    db_toggle_bookmark     = gContext->GetNumSetting("AltClearSavedPosition",1);
+    db_run_jobs_on_remote  = gContext->GetNumSetting("JobsRunOnRecordHost", 0);
+    db_use_dvd_bookmark    = gContext->GetNumSetting("EnableDVDBookmark", 0);
+    db_continue_embedded   = gContext->GetNumSetting(
+        "ContinueEmbeddedTVPlay", 0);
+    db_use_fixed_size      = gContext->GetNumSettingOnHost(
+        "UseFixedWindowSize", gContext->GetHostName(), 1);
 
     sleep_times.push_back(SleepTimerInfo(QObject::tr("Off"),       0));
     sleep_times.push_back(SleepTimerInfo(QObject::tr("30m"),   30*60));
@@ -662,8 +682,8 @@
 
     playerLock.lockForWrite();
     player.push_back(new PlayerContext());
+    playerActive = 0;
     playerLock.unlock();
-    SetActive(NULL, 0);
 }
 
 /** \fn TV::Init(bool)
@@ -768,9 +788,6 @@
             }
         }
 
-        bool use_fixed_size = gContext->GetNumSettingOnHost(
-            "UseFixedWindowSize", gContext->GetHostName(), 1);
-
         // player window sizing
         myWindow = new MythDialog(mainWindow, "video playback window");
 
@@ -780,18 +797,18 @@
         myWindow->setGeometry(win_bounds);
         myWindow->setBaseSize(win_bounds.size());
         myWindow->setMinimumSize(
-            (use_fixed_size) ? win_bounds.size() : QSize(16, 16));
+            (db_use_fixed_size) ? win_bounds.size() : QSize(16, 16));
         myWindow->setMaximumSize(
-            (use_fixed_size) ? win_bounds.size() :
+            (db_use_fixed_size) ? win_bounds.size() :
             QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
 
         // resize main window
         mainWindow->setGeometry(player_bounds);
         mainWindow->setBaseSize(player_bounds.size());
         mainWindow->setMinimumSize(
-            (use_fixed_size) ? player_bounds.size() : QSize(16, 16));
+            (db_use_fixed_size) ? player_bounds.size() : QSize(16, 16));
         mainWindow->setMaximumSize(
-            (use_fixed_size) ? player_bounds.size() :
+            (db_use_fixed_size) ? player_bounds.size() :
             QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
         mainWindow->installEventFilter(this);
 
@@ -834,7 +851,7 @@
         mwnd->resize(saved_gui_bounds.size());
         mwnd->setFixedSize(saved_gui_bounds.size());
         mwnd->show();
-        if (!gContext->GetNumSetting("GuiSizeForTV", 0))
+        if (!db_use_gui_size_for_tv)
             mwnd->move(saved_gui_bounds.topLeft());
     }
 
@@ -923,7 +940,7 @@
                     .arg(db_idle_timeout*(1.0f/60000.0f)));
         }
 
-        if (startInGuide || gContext->GetNumSetting("WatchTVGuide", 0))
+        if (startInGuide || db_start_in_guide)
         {
             MSqlQuery query(MSqlQuery::InitCon());
             query.prepare("SELECT keylist FROM keybindings WHERE "
@@ -1336,7 +1353,7 @@
                 break;
             case 2:
                 // return to main menu
-                StopLiveTV();
+                SetExitPlayer(true, true);
                 break;
             case 3:
                 // cancel scheduled recording
@@ -1353,7 +1370,7 @@
             default:
             case 1:
                 // return to main menu
-                StopLiveTV();
+                SetExitPlayer(true, true);
                 break;
             case 2:
             {
@@ -1628,7 +1645,7 @@
         {
             // Cache starting frame rate for this recorder
             ctx->last_framerate = ctx->recorder->GetFrameRate();
-            ok = StartPlayer(mctx, ctx, desiredNextState, ctx->isPIP());
+            ok = StartPlayer(mctx, ctx, desiredNextState);
         }
         if (!ok)
         {
@@ -1648,12 +1665,18 @@
                 lockTimerOn = true;
             }
         }
+
+        if (mctx != ctx)
+            SetActive(ctx, find_player_index(ctx), false);
     }
     else if (TRANSITION(kState_WatchingLiveTV, kState_None))
     {
         SET_NEXT();
         RestoreScreenSaver(ctx);
         StopStuff(mctx, ctx, true, true, true);
+
+        if ((mctx != ctx) && (GetPlayer(ctx,-1) == ctx))
+            SetActive(mctx, 0, true);
     }
     else if (TRANSITION(kState_WatchingRecording, kState_WatchingPreRecorded))
     {
@@ -1704,7 +1727,7 @@
                 }
             }
 
-            ok = StartPlayer(mctx, ctx, desiredNextState, ctx->isPIP());
+            ok = StartPlayer(mctx, ctx, desiredNextState);
 
             if (ok)
             {
@@ -1727,6 +1750,10 @@
             SET_LAST();
             SetErrored(ctx);
         }
+        else if (mctx != ctx)
+        {
+            SetActive(ctx, find_player_index(ctx), false);
+        }
     }
     else if (TRANSITION(kState_WatchingPreRecorded, kState_None) ||
              TRANSITION(kState_WatchingRecording, kState_None))
@@ -1735,6 +1762,9 @@
 
         RestoreScreenSaver(ctx);
         StopStuff(mctx, ctx, true, true, false);
+
+        if ((mctx != ctx) && (GetPlayer(ctx,-1) == ctx))
+            SetActive(mctx, 0, true);
     }
     else if (TRANSITION(kState_None, kState_None))
     {
@@ -1754,6 +1784,9 @@
 
         nextState = kState_None;
         changed = true;
+
+        if ((mctx != ctx) && (GetPlayer(ctx,-1) == ctx))
+            SetActive(mctx, 0, true);
     }
 
     // Print state changed message...
@@ -1901,7 +1934,7 @@
             LOC + QString("StopStuff() for player ctx %1 -- begin")
             .arg(find_player_index(ctx)));
 
-    SetActive(mctx, 0);
+    SetActive(mctx, 0, false);
 
     if (ctx->buffer && ctx->buffer->isDVD())
     {
@@ -1951,20 +1984,27 @@
     QString loc = LOC + QString("TeardownPlayer() player ctx %1")
         .arg(ctx_index);
 
-    SetActive(mctx, 0);
+    if (!mctx || !ctx || ctx_index < 0)
+    {
+        VERBOSE(VB_IMPORTANT, loc + "-- error");
+        return;
+    }
 
+    VERBOSE(VB_PLAYBACK, loc);
+
     if (mctx != ctx)
     {
         if (ctx->nvp)
         {
+            PIPRemovePlayer(mctx, ctx);
             ctx->nvp->StopPlaying();
             ctx->SetNVP(NULL);
         }
 
-        SetPIPPlayer(mctx, ctx);
         player.erase(player.begin() + ctx_index);
         delete ctx;
-        TeardownPBP(ctx);
+        PBPRestartMainNVP(mctx);
+        SetActive(mctx, playerActive, false);
         return;
     }
 
@@ -2022,7 +2062,7 @@
     mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
     if (!mctx->IsErrored() && (GetState(mctx) != kState_None))
     {
-        mctx->ForceNextStateNone();
+        mctx->ForceNextStateNone(__LINE__);
         HandleStateChange(mctx, mctx);
         if (jumpToProgram)
             TeardownPlayer(mctx, mctx);
@@ -2076,6 +2116,8 @@
         HandlePseudoLiveTVTimerEvent();
     else if (timer_id == speedChangeTimerId)
         HandleSpeedChangeTimerEvent();
+    else if (timer_id == pipChangeTimerId)
+        HandlePxPTimerEvent();
     else
         handled = false;
 
@@ -2275,7 +2317,6 @@
 
     // Check if it matches networkControlTimerId
     QString netCmd = QString::null;
-    if (!ignoreKeys)
     {
         QMutexLocker locker(&timerIdLock);
         if (timer_id == networkControlTimerId)
@@ -2292,7 +2333,7 @@
 
     if (!netCmd.isEmpty())
     {
-        PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
+        PlayerContext *actx = GetPlayerWriteLock(-1, __FILE__, __LINE__);
         ProcessNetworkControlCommand(actx, netCmd);
         ReturnPlayerLock(actx);
         handled = true;
@@ -2329,16 +2370,16 @@
                 }
                 ReturnOSDLock(mctx, osd);
                 lastProgramStringList.clear();
-                setLastProgram(NULL);
+                SetLastProgram(NULL);
                 VERBOSE(VB_PLAYBACK, LOC_ERR +
                             "Last Program File does not exist");
                 jumpToProgram = false;
             }
             else
-                ForceNextStateNone(mctx);
+                ForceNextStateNone(mctx, __LINE__);
         }
         else
-            ForceNextStateNone(mctx);
+            ForceNextStateNone(mctx, __LINE__);
 
         ReturnPlayerLock(mctx);
 
@@ -2364,51 +2405,6 @@
     if (handled)
         return;
 
-    if (timer_id == pipChangeTimerId)
-    {
-        if (needToMakePIPChange > kPIPOff)
-        {
-            PlayerContext *mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
-            ClearOSD(mctx);
-
-            switch (needToMakePIPChange)
-            {
-                case (kPIPSwap):
-                    SwapPIP(mctx, 1, false);
-                    break;
-                case (kPBPSwap):
-                    SwapPIP(mctx, 1, true);
-                    break;
-                case (kPIPToPBP):
-                    TogglePIPState(mctx, needToMakePIPChange);
-                    break;
-                case (kPBPToPIP):
-                    TogglePIPState(mctx, needToMakePIPChange);
-                    break;
-                case (kPBPToggle):
-                {
-                    if (mctx && (player.size() > 1))
-                        TeardownPlayer(mctx, GetPlayer(mctx, 1));
-                    else
-                        TogglePIPView(mctx, true);
-                    break;
-                }
-            }
-            ReturnPlayerLock(mctx);
-
-            needToMakePIPChange = kPIPOff;
-        }
-
-        QMutexLocker locker(&timerIdLock);
-        if (pipChangeTimerId)
-            KillTimer(pipChangeTimerId);
-        pipChangeTimerId = 0;
-        handled = true;
-    }
-
-    if (handled)
-        return;
-
     if (timer_id == udpNotifyTimerId)
     {
         while (HasUDPNotifyEvent())
@@ -2555,7 +2551,9 @@
     {
         PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
         OSD *osd = GetOSDLock(actx);
-        OSDSet *oset = osd->GetSet("status");
+        OSDSet *oset = NULL;
+        if (osd)
+            oset = osd->GetSet("status");
         if (osd && oset && oset->Displaying() &&
             (StateIsLiveTV(actx->GetState()) ||
              StateIsPlaying(actx->GetState())))
@@ -2580,7 +2578,7 @@
             (mctx->nvp && mctx->nvp->IsErrored()) || mctx->IsErrored())
         {
             SetExitPlayer(true, false);
-            ForceNextStateNone(mctx);
+            ForceNextStateNone(mctx, __LINE__);
             error = true;
         }
 
@@ -2588,7 +2586,7 @@
         {
             PlayerContext *ctx = GetPlayer(mctx, i);
             if (error || ctx->IsErrored())
-                ForceNextStateNone(ctx);
+                ForceNextStateNone(ctx, __LINE__);
         }
         ReturnPlayerLock(mctx);
 
@@ -2600,6 +2598,53 @@
     }
 }
 
+bool TV::HandlePxPTimerEvent(void)
+{
+    QString cmd = QString::null;
+
+    {
+        QMutexLocker locker(&timerIdLock);
+        if (changePxP.empty())
+        {
+            if (pipChangeTimerId)
+                KillTimer(pipChangeTimerId);
+            pipChangeTimerId = 0;
+            return true;
+        }
+        cmd = changePxP.dequeue();
+    }
+
+    PlayerContext *mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
+    PlayerContext *actx = GetPlayer(mctx, -1);
+
+    if (cmd == "TOGGLEPIPMODE")
+        PxPToggleView(actx, false);
+    else if (cmd == "TOGGLEPBPMODE")
+        PxPToggleView(actx, true);
+    else if (cmd == "CREATEPIPVIEW")
+        PxPCreateView(actx, false);
+    else if (cmd == "CREATEPBPVIEW")
+        PxPCreateView(actx, true);
+    else if (cmd == "SWAPPIP")
+        PxPSwap(mctx);
+    else if (cmd == "TOGGLEPIPSTATE")
+        PxPToggleType(mctx, !mctx->isPBP());
+
+    ReturnPlayerLock(mctx);
+
+    QMutexLocker locker(&timerIdLock);
+
+    if (pipChangeTimerId)
+        KillTimer(pipChangeTimerId);
+
+    if (changePxP.empty())
+        pipChangeTimerId = 0;
+    else
+        pipChangeTimerId = StartTimer(20, __LINE__);
+
+    return true;
+}
+
 bool TV::HandleLCDTimerEvent(void)
 {
     PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
@@ -2654,9 +2699,9 @@
     QObject::killTimer(id);
 }
 
-void TV::ForceNextStateNone(PlayerContext *ctx)
+void TV::ForceNextStateNone(PlayerContext *ctx, int line)
 {
-    ctx->ForceNextStateNone();
+    ctx->ForceNextStateNone(line);
     ScheduleStateChange(ctx);
 }
 
@@ -2674,8 +2719,11 @@
     errorRecoveryTimerId = StartTimer(1, __LINE__);
 }
 
-void TV::SetExitPlayer(bool set_it, bool wants_to) const
+void TV::SetExitPlayerReal(bool set_it, bool wants_to, int line) const
 {
+    VERBOSE(VB_IMPORTANT,
+            LOC + "SetExitPlayer("<<set_it<<","<<wants_to<<","<<line<<")");
+
     QMutexLocker locker(&timerIdLock);
     if (set_it)
     {
@@ -2731,7 +2779,7 @@
             continue;
         }
 
-        ForceNextStateNone(ctx);
+        ForceNextStateNone(ctx, __LINE__);
         if (mctx == ctx)
         {
             endOfRecording = true;
@@ -3065,8 +3113,10 @@
 
 void TV::ProcessKeypress(PlayerContext *actx, QKeyEvent *e)
 {
+    bool ignoreKeys = actx->IsNVPChangingBuffers();
 #if DEBUG_ACTIONS
-    VERBOSE(VB_IMPORTANT, LOC + "ProcessKeypress() ignoreKeys: "<<ignoreKeys);
+    VERBOSE(VB_IMPORTANT, LOC + QString("ProcessKeypress() ignoreKeys: %1")
+            .arg(ignoreKeys));
 #endif // DEBUG_ACTIONS
 
     if (db_idle_timeout > 0)
@@ -3191,7 +3241,7 @@
     handled = handled || DVDMenuHandleAction(actx, actions, isDVD, isDVDStill);
     handled = handled || ActiveHandleAction(actx, actions, isDVD, isDVDStill);
     handled = handled || ToggleHandleAction(actx, actions, isDVD);
-    handled = handled || PIPHandleAction(actx, actions);
+    handled = handled || PxPHandleAction(actx, actions);
     handled = handled || FFRewHandleAction(actx, actions);
     handled = handled || ActivePostQHandleAction(actx, actions, isDVD);
 
@@ -3223,11 +3273,10 @@
 
 bool TV::BrowseHandleAction(PlayerContext *ctx, const QStringList &actions)
 {
-    bool handled = false;
     if (!browsemode)
-        return handled;
+        return false;
 
-    handled = true;
+    bool handled = true;
 
     if (has_action("UP", actions) || has_action("CHANNELUP", actions))
         BrowseDispInfo(ctx, BROWSE_UP);
@@ -3254,6 +3303,7 @@
         ToggleRecord(ctx);
     else
     {
+        handled = false;
         QStringList::const_iterator it = actions.begin();
         for (; it != actions.end(); ++it)
         {
@@ -3262,24 +3312,25 @@
             {
                 CommitQueuedInput(ctx);
                 BrowseEnd(ctx, false);
+                handled = true;
             }
         }
     }
 
     // only pass-through actions listed below
-    return !(has_action("VOLUMEDOWN",      actions) ||
-             has_action("VOLUMEUP",        actions) ||
-             has_action("STRETCHINC",      actions) ||
-             has_action("STRETCHDEC",      actions) ||
-             has_action("MUTE",            actions) ||
-             has_action("TOGGLEASPECT",    actions) ||
-             has_action("TOGGLEPIPWINDOW", actions) ||
-             has_action("TOGGLEPIPMODE",   actions) ||
-             has_action("TOGGLEPIPSTATE",  actions) ||
-             has_action("SWAPPIP",         actions));
-
-    // TODO FIXME this is never reached.. must be a logic error
-    return handled;
+    return handled ||
+        !(has_action("VOLUMEDOWN",      actions) ||
+          has_action("VOLUMEUP",        actions) ||
+          has_action("STRETCHINC",      actions) ||
+          has_action("STRETCHDEC",      actions) ||
+          has_action("MUTE",            actions) ||
+          has_action("TOGGLEASPECT",    actions) ||
+          has_action("TOGGLEPIPMODE",   actions) ||
+          has_action("TOGGLEPIPSTATE",  actions) ||
+          has_action("NEXTPIPWINDOW",   actions) ||
+          has_action("CREATEPIPVIEW",   actions) ||
+          has_action("CREATEPBPVIEW",   actions) ||
+          has_action("SWAPPIP",         actions));
 }
 
 bool TV::ManualZoomHandleAction(PlayerContext *actx, const QStringList &actions)
@@ -3467,14 +3518,7 @@
         }
         else if (dialogname == "allowrecordingbox")
         {
-            int result = osd->GetDialogResponse(dialogname);
-
-            if (result == 1)
-                actx->recorder->CancelNextRecording(false);
-            else if (result == 2)
-                StopLiveTV();
-            else if (result == 3)
-                actx->recorder->CancelNextRecording(true);
+            HandleOSDAskAllowResponse();
         }
         else if (dialogname == "idletimeout")
         {
@@ -3831,27 +3875,10 @@
     {
         ClearOSD(ctx);
     }
-    else if (has_action("JUMPPREV", actions))
-    {
-        if (PromptRecGroupPassword(ctx))
-        {
-            ctx->nvp->SetBookmark();
-            SetExitPlayer(true, true);
-        }
-    }
     else if (has_action("VIEWSCHEDULED", actions))
         EditSchedule(ctx, kViewSchedule);
-    else if (has_action("JUMPREC", actions))
+    else if (HandleJumpToProgramAction(ctx, actions))
     {
-        if (gContext->GetNumSetting("JumpToProgramOSD", 1) &&
-            StateIsPlaying(ctx->GetState()))
-        {
-            if (jumpMenuTimerId)
-                KillTimer(jumpMenuTimerId);
-            jumpMenuTimerId = StartTimer(1, __LINE__);
-        }
-        else if (RunPlaybackBoxPtr)
-            EditSchedule(ctx, kPlaybackBox);
     }
     else if (has_action("SIGNALMON", actions))
     {
@@ -3898,7 +3925,8 @@
     }
     else if (has_action("ESCAPE", actions))
     {
-        SetActive(ctx, 0);
+        VERBOSE(VB_IMPORTANT, LOC + "ESCAPE");
+
         osd = GetOSDLock(ctx);
         if (StateIsLiveTV(ctx->GetState()) &&
             (ctx->lastSignalMsgTime.elapsed() <
@@ -3917,40 +3945,58 @@
 
         StopFFRew(ctx);
 
+        bool do_exit = false;
+
         if (StateIsLiveTV(GetState(ctx)))
         {
             if (ctx->nvp &&
-                (12 & gContext->GetNumSetting("PlaybackExitPrompt")))
+                (12 & db_playback_exit_prompt))
             {
                 PromptStopWatchingRecording(ctx);
             }
             else
             {
-                SetExitPlayer(true, true);
+                do_exit = true;
             }
         }
         else
         {
             if (ctx->nvp &&
-                (5 & gContext->GetNumSetting("PlaybackExitPrompt")) &&
+                (5 & db_playback_exit_prompt) &&
                 !underNetworkControl && !isDVDStill)
             {
                 PromptStopWatchingRecording(ctx);
                 return handled;
             }
             else if (ctx->nvp &&
-                     (gContext->GetNumSetting("PlaybackExitPrompt") == 2))
+                     (db_playback_exit_prompt == 2))
             {
                 ctx->nvp->SetBookmark();
             }
             if (ctx->nvp &&
-                gContext->GetNumSetting("AutomaticSetWatched", 0))
+                db_auto_set_watched)
             {
                 ctx->nvp->SetWatched();
             }
             requestDelete = false;
-            SetExitPlayer(true, true);
+            do_exit = true;
         }
+
+        if (do_exit)
+        {
+            PlayerContext *mctx = GetPlayer(ctx, 0);
+            if (mctx != ctx)
+            { // A PIP is active, just tear it down..
+                PxPTeardownView(ctx);
+                return handled;
+            }
+            else
+            {
+                SetExitPlayer(true, true);
+            }
+        }
+
+        SetActive(ctx, 0, false);
     }
     else if (has_action("VOLUMEDOWN", actions))
         ChangeVolume(ctx, false);
@@ -4075,43 +4121,39 @@
     return handled;
 }
 
-bool TV::PIPHandleAction(PlayerContext *ctx, const QStringList &actions)
+bool TV::PxPHandleAction(PlayerContext *ctx, const QStringList &actions)
 {
-    bool handled = true;
-
     if (!IsPIPSupported(ctx))
-        return handled;
+        return false;
 
-    if (has_action("TOGGLEPIPMODE", actions))
-        TogglePIPView(ctx);
-    else if (has_action("TOGGLEPBPMODE", actions))
+    bool handled = true;
     {
-        needToMakePIPChange = kPBPToggle;
-        if (pipChangeTimerId)
-            KillTimer(pipChangeTimerId);
-        pipChangeTimerId = StartTimer(1, __LINE__);
+        QMutexLocker locker(&timerIdLock);
+
+        if (has_action("TOGGLEPIPMODE", actions))
+            changePxP.enqueue("TOGGLEPIPMODE");
+        else if (has_action("TOGGLEPBPMODE", actions))
+            changePxP.enqueue("TOGGLEPBPMODE");
+        else if (has_action("CREATEPIPVIEW", actions))
+            changePxP.enqueue("CREATEPIPVIEW");
+        else if (has_action("CREATEPBPVIEW", actions))
+            changePxP.enqueue("CREATEPBPVIEW");
+        else if (has_action("SWAPPIP", actions))
+            changePxP.enqueue("SWAPPIP");
+        else if (has_action("TOGGLEPIPSTATE", actions))
+            changePxP.enqueue("TOGGLEPIPSTATE");
+        else
+            handled = false;
+        
+        if (!changePxP.empty() && !pipChangeTimerId)
+            pipChangeTimerId = StartTimer(1, __LINE__);
     }
-    else if (has_action("SWAPPIP", actions))
+
+    if (has_action("NEXTPIPWINDOW", actions))
     {
-        needToMakePIPChange = (ctx->isPBP()) ? kPBPSwap : kPIPSwap;
-        if (pipChangeTimerId)
-            KillTimer(pipChangeTimerId);
-        pipChangeTimerId = StartTimer(1, __LINE__);
+        SetActive(ctx, -1, true);
+        handled = true;
     }
-    else if (has_action("TOGGLEPIPSTATE", actions))
-    {
-        if (ctx && player.size() > 1)
-        {
-            needToMakePIPChange = (ctx->isPBP()) ? kPBPToPIP : kPIPToPBP;
-            if (pipChangeTimerId)
-                KillTimer(pipChangeTimerId);
-            pipChangeTimerId = StartTimer(1, __LINE__);
-        }
-    }
-    else if (has_action("TOGGLEPIPWINDOW", actions))
-        ToggleActiveWindow(ctx, 1);
-    else
-        handled = false;
 
     return handled;
 }
@@ -4131,11 +4173,10 @@
             if (isDVD && ctx->buffer && ctx->buffer->DVD())
                 ctx->buffer->DVD()->JumpToTitle(false);
 
-            int clearpos = gContext->GetNumSetting("AltClearSavedPosition", 1);
             ctx->LockDeleteNVP(__FILE__, __LINE__);
             if (ctx->nvp)
             {
-                if (clearpos && ctx->nvp->GetBookmark())
+                if (db_toggle_bookmark && ctx->nvp->GetBookmark())
                     ctx->nvp->ClearBookmark();
                 else
                     ctx->nvp->SetBookmark();
@@ -4200,11 +4241,20 @@
 void TV::ProcessNetworkControlCommand(PlayerContext *ctx,
                                       const QString &command)
 {
+    bool ignoreKeys = ctx->IsNVPChangingBuffers();
 #ifdef DEBUG_ACTIONS
     VERBOSE(VB_IMPORTANT, LOC + "ProcessNetworkControlCommand(" +
-            QString("%1)").arg(command));
+            QString("%1) ignoreKeys: %2").arg(command).arg(ignoreKeys));
 #endif
 
+    if (ignoreKeys)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "Ignoring network control command"
+                "\n\t\t\tbecause ignoreKeys is set");
+        return;
+    }
+
     QStringList tokens = command.split(" ", QString::SkipEmptyParts);
     if (tokens.size() < 2)
     {
@@ -4365,7 +4415,7 @@
     {
         if (ctx->nvp)
             ctx->nvp->SetBookmark();
-        if (ctx->nvp && gContext->GetNumSetting("AutomaticSetWatched", 0))
+        if (ctx->nvp && db_auto_set_watched)
             ctx->nvp->SetWatched();
         SetExitPlayer(true, true);
     }
@@ -4549,7 +4599,7 @@
         swap(player[0],player[1]);
         player[0]->SetPIPState(kPIPOff);
         // End the old main context..
-        ForceNextStateNone(mctx);
+        ForceNextStateNone(mctx, __LINE__);
     }
 
     VERBOSE(VB_PLAYBACK, LOC + "CreatePBP() -- end : "<<ok);
@@ -4557,72 +4607,42 @@
 }
 
 /**
- * \brief tear down remaining PBP video and restore
- * fullscreen display 
+ * \brief create PIP.
+ * \param info programinfo for PIP to create. is NULL for LiveTV PIP
  */
-void TV::TeardownPBP(PlayerContext *ctx)
+bool TV::CreatePIP(PlayerContext *ctx, const ProgramInfo *info)
 {
     PlayerContext *mctx = GetPlayer(ctx, 0);
+    if (!mctx)
+        return false;
 
-    if (!mctx->nvp || !mctx->nvp->IsPlaying() || 
-        mctx->GetPIPState() < kPBPLeft || exitPlayerTimerId)
-    {
-        return;
-    }
+    VERBOSE(VB_PLAYBACK, LOC + "CreatePIP -- begin");
 
-    VERBOSE(VB_PLAYBACK, LOC  + "TeardownPBP -- begin");
-
-    long long mctx_frame = mctx->nvp->GetFramesPlayed();
-    mctx->PIPTeardown();
-    mctx->SetPIPState(kPIPOff);
-    mctx->buffer->Seek(0, SEEK_SET);
-    if (mctx->CreateNVP(this, myWindow, mctx->GetState(),
-                        embedWinID, &embedBounds))
+    if (mctx->isPBP())
     {
-        ScheduleStateChange(mctx);
-        mctx->StartOSD(this);
-        mctx->nvp->JumpToFrame(mctx_frame);
-
-        //TODO find out where wantsToQuit is been enabled
-        wantsToQuit = false;
-
-        SetSpeedChangeTimer(25, __LINE__);
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                "CreatePIP called, but we're in PBP mode already, ignoring.");
+        return false;
     }
-    else
-        ForceNextStateNone(mctx);
 
-    VERBOSE(VB_PLAYBACK, LOC + "TeardownPBP -- end");
-}
+    bool has_vo = false, using_xvmc = false;
 
-/**
- * \brief create PIP.
- * \param info programinfo for PIP to create. is NULL for LiveTV PIP
- */
-bool TV::CreatePIP(PlayerContext *ctx, const ProgramInfo *info)
-{
-    bool ret = false;
-    PlayerContext *mctx = GetPlayer(ctx, 0);
-
-    VERBOSE(VB_PLAYBACK, LOC + "Starting CreatePIP -- begin");
-    bool using_xvmc = false;
-    QRect rect;
-    int pip_location;
-    if (mctx && mctx->nvp && mctx->nvp->getVideoOutput())
+    mctx->LockDeleteNVP(__FILE__, __LINE__);
+    if (mctx->nvp && mctx->nvp->getVideoOutput())
     {
-        pip_location = gContext->GetNumSetting("PIPLocation", 0);
-        rect = mctx->nvp->getVideoOutput()->GetPIPRect(pip_location, NULL);
+        has_vo = true;
         using_xvmc = mctx->nvp->getVideoOutput()->hasMCAcceleration();
     }
-    else
-    {
-        return ret;
-    }
+    mctx->UnlockDeleteNVP(__FILE__, __LINE__);
 
+    if (!has_vo)
+        return false;
+
     /* TODO implement PIP solution for Xvmc playback */
     if (using_xvmc)
     {
         VERBOSE(VB_IMPORTANT, LOC + "PiP is not supported for XvMC");
-        return ret;
+        return false;
     }
 
     PlayerContext *pipctx = new PlayerContext();
@@ -4643,14 +4663,13 @@
     else
     {
         delete pipctx;
-        return ret;
+        return false;
     }
 
     // this is safe because we are already holding lock for ctx
     player.push_back(pipctx);
 
-    ret = true;
-    return ret;
+    return true;
 }
 
 int TV::find_player_index(const PlayerContext *ctx) const
@@ -4662,14 +4681,29 @@
 }
 
 bool TV::StartPlayer(PlayerContext *mctx, PlayerContext *ctx,
-                     TVState desiredState, bool ispip)
+                     TVState desiredState)
 {
-    if (ispip)
-        return StartPIPPlayer(mctx, ctx, desiredState);
+    bool wantPiP = ctx->isPIP();
 
-    VERBOSE(VB_IMPORTANT, LOC + QString("StartPlayer(%1, %2, not pip) -- begin")
-            .arg(find_player_index(ctx)).arg(StateToString(desiredState)));
+    VERBOSE(VB_IMPORTANT, LOC + QString("StartPlayer(%1, %2, %3) -- begin")
+            .arg(find_player_index(ctx)).arg(StateToString(desiredState))
+            .arg((wantPiP) ? "PiP" : "main"));
 
+    if (wantPiP)
+    {
+        if (mctx->nvp && ctx->StartPIPPlayer(this, desiredState) &&
+            ctx->nvp && PIPAddPlayer(mctx, ctx))
+        {
+            ScheduleStateChange(ctx);
+            VERBOSE(VB_IMPORTANT, "StartPlayer PiP -- end : ok");
+            return true;
+        }
+
+        ForceNextStateNone(ctx, __LINE__);
+        VERBOSE(VB_IMPORTANT, "StartPlayer PiP -- end : !ok");
+        return false;
+    }
+
     InitUDPNotifyEvent();
     bool ok = false;
     if (ctx->UseNullVideo())
@@ -4677,7 +4711,7 @@
         ok = ctx->CreateNVP(this, NULL, desiredState, 0, NULL);
         ScheduleStateChange(ctx);
         if (ok)
-            SetPIPPlayer(mctx, ctx);
+            ok = PIPAddPlayer(mctx, ctx);
     }
     else
     {
@@ -4692,208 +4726,270 @@
         SetSpeedChangeTimer(25, __LINE__);
     }
 
-    VERBOSE(VB_IMPORTANT, LOC +
-            QString("StartPlayer(%1, %2, not pip) -- end %3")
+    VERBOSE(VB_IMPORTANT, LOC + QString("StartPlayer(%1, %2, %3) -- end %4")
             .arg(find_player_index(ctx)).arg(StateToString(desiredState))
-            .arg((ok) ? "ok" : "error"));
+            .arg((wantPiP) ? "PiP" : "main").arg((ok) ? "ok" : "error"));
 
     return ok;
 }
 
-bool TV::StartPIPPlayer(PlayerContext *mctx, PlayerContext *ctx,
-                        TVState desiredState)
+/// \brief Maps NVP of software scaled PIP to the NVP of the main player
+bool TV::PIPAddPlayer(PlayerContext *mctx, PlayerContext *pipctx)
 {
-    if (mctx->nvp && ctx->StartPIPPlayer(this, desiredState) && ctx->nvp)
+    if (!mctx || !pipctx)
+        return false;
+
+    if (!mctx->nvp || !mctx->nvp->IsPlaying())
+        return false;
+
+    bool ok = false, addCondition = false;
+    if (pipctx->nvp)
     {
-        SetPIPPlayer(mctx, ctx);
-        ScheduleStateChange(ctx);
-        return true;
+        if (pipctx->nvp->UsingNullVideo())
+        {
+            addCondition = true;
+            PIPLocation loc = mctx->nvp->GetNextPIPLocation();
+            ok = mctx->nvp->AddPIPPlayer(pipctx->nvp, loc, 4000);
+        }
+        else if (pipctx->isPIP())
+        {
+            ok = ResizePIPWindow(pipctx);
+        }
     }
-    return false;
+
+    VERBOSE(VB_IMPORTANT,
+            QString("AddPIPPlayer null: %1 isPIP: %2 addCond: %3 ok: %4")
+            .arg(pipctx->nvp->UsingNullVideo())
+            .arg(pipctx->isPIP()).arg(addCondition).arg(ok));
+
+    return ok;
 }
 
-/**
- * \brief maps NVP of software scaled PIP  to the NVP of player
- * context 0.
- */
-void TV::SetPIPPlayer(PlayerContext *mctx, PlayerContext *pipctx)
+/// \brief Unmaps NVP of software scaled PIP from the NVP of the main player
+bool TV::PIPRemovePlayer(PlayerContext *mctx, PlayerContext *pipctx)
 {
     if (!mctx || !pipctx)
+        return false;
+
+    bool ok = false;
+    if (mctx->nvp && pipctx->nvp)
+        ok = mctx->nvp->RemovePIPPlayer(pipctx->nvp, 4000);
+
+    VERBOSE(VB_IMPORTANT, QString("PIPRemovePlayer ok: %1").arg(ok));
+
+    return ok;
+}
+
+/// \brief start/stop PIP/PBP
+void TV::PxPToggleView(PlayerContext *actx, bool wantPBP)
+{
+    if (player.size() <= 1)
+        PxPCreateView(actx, wantPBP);
+    else
+        PxPTeardownView(actx);
+}
+
+/// \brief start PIP/PBP
+void TV::PxPCreateView(PlayerContext *actx, bool wantPBP)
+{
+    if (!actx)
         return;
 
-    bool setCondition = false;
-    if (mctx->nvp && mctx->nvp->IsPlaying())
+    QString err_msg = QString::null;
+    if ((player.size() > kMaxPBPCount) && (wantPBP || actx->isPBP()))
     {
-        if (pipctx->nvp)
-        {
-            if (pipctx->nvp->UsingNullVideo())
-                setCondition = true;
-            else if (playerActive == 0 && pipctx->isPIP())
-                ResizePIPWindow(pipctx);
-        }
-        else
-            setCondition = true;
+        err_msg = tr("Sorry, PBP only supports %1 video streams")
+            .arg(kMaxPBPCount);
+    }
 
-        if (setCondition)
-        {
-            QMutex piplock;
-            piplock.lock();
-            mctx->nvp->SetPIPPlayer(pipctx->nvp);
-            pipPlayerSetCondition.wait(&piplock);
-            piplock.unlock();
-        }
+    if ((player.size() > kMaxPIPCount) &&
+        (!wantPBP || GetPlayer(actx,1)->isPIP()))
+    {
+        err_msg = tr("Sorry, PIP only supports %1 video streams")
+            .arg(kMaxPIPCount);
     }
+
+    if ((player.size() > 1) && (wantPBP ^ actx->isPBP()))
+        err_msg = tr("Sorry, can not mix PBP and PIP views");
+
+    if (!err_msg.isEmpty())
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + err_msg);
+        OSD *osd = GetOSDLock(actx);
+        if (osd)
+            osd->SetSettingsText(err_msg, 3);
+        ReturnOSDLock(actx, osd);
+        return;
+    }
+
+    bool ok = false;
+    if (wantPBP)
+        ok = CreatePBP(actx, NULL);
+    else
+        ok = CreatePIP(actx, NULL);
+    actx = GetPlayer(actx, -1); // CreatePBP/PIP mess with ctx's
+
+    QString msg = (ok) ?
+        ((wantPBP) ? tr("Creating PBP")      : tr("Creating PIP")) :
+        ((wantPBP) ? tr("Cannot create PBP") : tr("Cannot create PIP"));
+    
+    OSD *osd = GetOSDLock(actx);
+    if (osd)
+        osd->SetSettingsText(msg, 3);
+    ReturnOSDLock(actx, osd);
 }
 
-/**
- * \brief start/stop PIP/PBP
- *
- */
-void TV::TogglePIPView(PlayerContext *lctx, bool ispbp)
+/// \brief stop PIP/PBP
+void TV::PxPTeardownView(PlayerContext *actx)
 {
+    VERBOSE(VB_IMPORTANT, "PxPTeardownView()");
+
     QString msg;
+    PlayerContext *mctx = GetPlayer(actx, 0);
+    PlayerContext *dctx = NULL;
+    dctx = (mctx != actx)       ? actx               : dctx;
+    dctx = (2 == player.size()) ? GetPlayer(actx, 1) : dctx;
 
-    if (player.size() > 1)
+    SetActive(actx, 0, false);
+
+    PlayerContext *ctx1 = GetPlayer(actx, 1);
+    msg = (ctx1->isPIP()) ? tr("Stopping PIP") : tr("Stopping PBP");
+    if (dctx)
     {
-        PlayerContext *ctx = player.back();
-        msg = "Stopping ";
-        msg += (ctx->isPIP()) ? "PIP" : "PBP";
-        if (playerActive != 0)
-            ToggleActiveWindow(lctx, 1);
-        ForceNextStateNone(ctx);
+        ForceNextStateNone(dctx, __LINE__);
     }
     else
     {
-        bool ok = false;
-        if (ispbp)
-            ok = CreatePBP(lctx, NULL);
-        else
-            ok = CreatePIP(lctx, NULL);
-        lctx = GetPlayer(lctx, -1); // CreatePBP/PIP mess with ctx's
-
-        if (!ok)
+        if (player.size() > 2)
         {
-            msg = "Cannot Start ";
-            msg += (ispbp) ? "PBP" : "PIP";
+            msg = (ctx1->isPIP()) ?
+                tr("Stopping all PIPs") : tr("Stopping all PBPs");
         }
+
+        for (uint i = player.size() - 1; i > 0; i--)
+            ForceNextStateNone(GetPlayer(actx,i), __LINE__);
     }
 
-    OSD *osd = GetOSDLock(lctx);
+    OSD *osd = GetOSDLock(mctx);
     if (osd)
         osd->SetSettingsText(msg, 3);
-    ReturnOSDLock(lctx, osd);
+    ReturnOSDLock(mctx, osd);
 }
 
 /**
 * \brief Change PIP View from PIP to PBP and visa versa
 */
-void TV::TogglePIPState(PlayerContext *mctx, PIPState changeTo)
+void TV::PxPToggleType(PlayerContext *mctx, bool wantPBP)
 {
-    QString before = (changeTo == kPIPToPBP) ? "PIP" : "PBP";
-    QString after  = (changeTo == kPIPToPBP) ? "PBP" : "PIP";
+    const QString before = (mctx->isPBP()) ? "PBP" : "PIP";
+    const QString after  = (wantPBP)       ? "PBP" : "PIP";
+
     VERBOSE(VB_PLAYBACK, LOC +
-            QString("TogglePIPState() converting from %1 to %2 -- begin")
-                    .arg(before).arg(after));
+            QString("PxPToggleType() converting from %1 to %2 -- begin")
+            .arg(before).arg(after));
 
-    if (2 != player.size())
+    if (mctx->isPBP() == wantPBP)
     {
-        VERBOSE(VB_IMPORTANT, LOC_ERR +
-                QString("TogglePIPState() -- end: # player contexts must be 2, "
-                        "but it is currently %1").arg(player.size()));
+        VERBOSE(VB_IMPORTANT, LOC_WARN +
+                "PxPToggleType() -- end: already in desired mode");
         return;
     }
 
-    SetActive(mctx, 0);
+    uint max_cnt = min(kMaxPBPCount, kMaxPIPCount);
+    if (player.size() > max_cnt)
+    {
+        VERBOSE(VB_IMPORTANT, LOC_ERR +
+                QString("PxPToggleType() -- end: "
+                        "# player contexts must be %1 or less, "
+                        "but it is currently %1")
+                .arg(max_cnt).arg(player.size()));
 
-    PlayerContext *pipctx = GetPlayer(mctx, 1);
+        QString err_msg = tr("Too many views to switch");
 
-    if (!mctx->nvp || !pipctx->nvp || !pipctx->nvp->IsPlaying())
+        PlayerContext *actx = GetPlayer(mctx, -1);
+        OSD *osd = GetOSDLock(actx);
+        if (osd)
+            osd->SetSettingsText(err_msg, 3);
+        ReturnOSDLock(actx, osd);
         return;
+    }
 
+    for (uint i = 0; i < player.size(); i++)
+    {
+        PlayerContext *ctx = GetPlayer(mctx, i);
+        ctx->LockDeleteNVP(__FILE__, __LINE__);
+        if (!ctx->nvp || !ctx->nvp->IsPlaying())
+        {
+            ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "PxPToggleType() -- end: " +
+                    QString("nvp #%1 is not active, exiting without "
+                            "doing anything to avoid danger").arg(i));
+            return;
+        }
+        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+    }
+
     MuteState mctx_mute = mctx->nvp->GetMuteState();
 
-    vector<long long> pos;
-    pos.push_back(mctx->nvp->GetFramesPlayed());
-    pos.push_back(pipctx->nvp->GetFramesPlayed());
+    vector<long long> pos = TeardownAllNVPs(mctx);
 
-    TeardownPIPWindows(mctx);
-
-    if (changeTo == kPIPToPBP)
+    if (wantPBP)
     {
-        mctx->SetPIPState(kPBPLeft);
-        pipctx->SetPIPState(kPBPRight);
+        GetPlayer(mctx, 0)->SetPIPState(kPBPLeft);
+        GetPlayer(mctx, 1)->SetPIPState(kPBPRight);
     }
     else
     {
-        mctx->SetPIPState(kPIPOff);
-        pipctx->SetPIPState(kPIPonTV);
-        pipctx->SetNullVideo(true);
+        GetPlayer(mctx, 0)->SetPIPState(kPIPOff);
+        for (uint i = 1; i < player.size(); i++)
+        {
+            GetPlayer(mctx, i)->SetPIPState(kPIPonTV);
+            GetPlayer(mctx, i)->SetNullVideo(true);
+        }
     }
 
-    RestartPIPWindows(mctx, pos, mctx_mute);
+    RestartAllNVPs(mctx, pos, mctx_mute);
 
     VERBOSE(VB_PLAYBACK, LOC +
-            QString("TogglePIPState() converting from %1 to %2 -- end")
+            QString("PxPToggleType() converting from %1 to %2 -- end")
             .arg(before).arg(after));
 }
 
-void TV::ToggleActiveWindow(PlayerContext *lctx, int ctx_index)
+/**
+ * \brief resize PIP Window. done when changing channels or swapping PIP
+ */
+bool TV::ResizePIPWindow(PlayerContext *ctx)
 {
-    if (player.size() == 1 || ctx_index < 1)
-        return;
-
-    ClearOSD(lctx);
-
-    PlayerContext *ctx = GetPlayer(lctx, ctx_index);
-    if (ctx->nvp)
+    VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- begin");
+    PlayerContext *mctx = GetPlayer(ctx, 0);
+    if (mctx->nvp && ctx->nvp)
     {
-        int new_index = 0;
-        lockTimerOn = false;
+        QRect rect;
 
-        if (playerActive != ctx_index)
-            new_index = ctx_index;
+        mctx->LockDeleteNVP(__FILE__, __LINE__);
+        if (mctx->nvp)
+        {
+            PIPLocation loc = mctx->nvp->GetNextPIPLocation();
+            VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- loc "<<loc);
+            if (loc != kPIP_END)
+            {
+                rect = mctx->nvp->getVideoOutput()->GetPIPRect(
+                    loc, ctx->nvp, false);
+            }
+        }
+        mctx->UnlockDeleteNVP(__FILE__, __LINE__);
 
-        PlayerContext *mctx = GetPlayer(lctx, 0);
-        if (mctx->nvp && 
-            mctx->nvp->getVideoOutput() && 
-            !ctx->isPBP())
+        if (rect.isValid())
         {
-            mctx->nvp->getVideoOutput()->PadPIPImage(new_index);
+            ctx->ResizePIPWindow(rect);
+            VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- end : ok");
+            return true;
         }
-
-        SetActive(lctx, new_index);
     }
-
-    PlayerContext *actx = GetPlayer(lctx, -1);
-    OSD *osd = GetOSDLock(actx);
-    if (osd)
-        osd->SetSettingsText(tr("Changed Active Window"), 3);
-    ReturnOSDLock(actx, osd);
+    VERBOSE(VB_PLAYBACK, LOC + "ResizePIPWindow -- end : !ok");
+    return false;
 }
 
-/**
- * \brief wake TV thread when pip player var is set in the main NVP
- */
-void TV::WakeSetPIPPlayerCond(void)
-{
-    pipPlayerSetCondition.wakeAll();
-}
-
-/**
- * \brief resize PIP Window. done when changing channels or swapping PIP
- */
-void TV::ResizePIPWindow(PlayerContext *ctx)
-{
-    PlayerContext *actx = GetPlayer(ctx, -1);
-    int loc = gContext->GetNumSetting("PIPLocation", 0);
-    if (actx->nvp && ctx->nvp)
-    {
-        QRect rect = 
-            actx->nvp->getVideoOutput()->GetPIPRect(loc, ctx->nvp, false);
-        ctx->ResizePIPWindow(rect);
-    }
-}
-
 bool TV::IsPIPSupported(const PlayerContext *ctx) const
 {
     const PlayerContext *mctx = NULL;
@@ -4910,28 +5006,77 @@
     return yes;
 }
 
-/**
-* \brief Teardown all NVP's in preparation for PIP Swap or change from PIP <-> PBP
-*/
-void TV::TeardownPIPWindows(PlayerContext *lctx)
+/** \brief Teardown all NVP's in preparation for PxP Swap or
+ *         change from PIP -> PBP or PBP -> PIP
+ */
+vector<long long> TV::TeardownAllNVPs(PlayerContext *lctx)
 {
-    SetActive(lctx, 0);
+    vector<long long> pos;
+    for (uint i = 0; i < player.size(); i++)
+    {
+        const PlayerContext *ctx = GetPlayer(lctx, i);
+        ctx->LockDeleteNVP(__FILE__, __LINE__);
+        pos.push_back((ctx->nvp) ? ctx->nvp->GetFramesPlayed() : 0);
+        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+    }
 
     for (uint i = 0; i < player.size(); i++)
     {
         PlayerContext *ctx = GetPlayer(lctx, i);
         ctx->PIPTeardown();
     }
+
+    return pos;
 }
 
 /**
+ * \brief tear down remaining PBP video and restore
+ * fullscreen display 
+ */
+void TV::PBPRestartMainNVP(PlayerContext *mctx)
+{
+    VERBOSE(VB_PLAYBACK, LOC  + "PBPRestartMainNVP -- begin");
+
+    mctx->LockDeleteNVP(__FILE__, __LINE__);
+    if (!mctx->nvp || !mctx->nvp->IsPlaying() || 
+        mctx->GetPIPState() != kPBPLeft || exitPlayerTimerId)
+    {
+        mctx->UnlockDeleteNVP(__FILE__, __LINE__);
+        VERBOSE(VB_PLAYBACK, LOC  + "PBPRestartMainNVP -- end !ok !valid");
+        return;
+    }
+
+    long long mctx_frame = mctx->nvp->GetFramesPlayed();
+    mctx->UnlockDeleteNVP(__FILE__, __LINE__);
+
+    mctx->PIPTeardown();
+    mctx->SetPIPState(kPIPOff);
+    mctx->buffer->Seek(0, SEEK_SET);
+
+    if (mctx->CreateNVP(this, myWindow, mctx->GetState(),
+                        embedWinID, &embedBounds))
+    {
+        ScheduleStateChange(mctx);
+        mctx->StartOSD(this);
+        mctx->nvp->JumpToFrame(mctx_frame);
+        SetSpeedChangeTimer(25, __LINE__);
+        VERBOSE(VB_PLAYBACK, LOC + "PBPRestartMainNVP -- end ok");
+        return;
+    }
+
+    ForceNextStateNone(mctx, __LINE__);
+    VERBOSE(VB_PLAYBACK, LOC +
+            "PBPRestartMainNVP -- end !ok NVP did not restart");
+}
+
+/**
 * \brief Recreate Main and PIP windows. Could be either PIP or PBP views.
 */
-void TV::RestartPIPWindows(PlayerContext *lctx,
-                           const vector<long long> &pos,
-                           MuteState mctx_mute)
+void TV::RestartAllNVPs(PlayerContext *lctx,
+                        const vector<long long> &pos,
+                        MuteState mctx_mute)
 {
-    QString loc = LOC + QString("RestartPIPWindows()");
+    QString loc = LOC + QString("RestartAllNVPs(): ");
 
     PlayerContext *mctx = GetPlayer(lctx, 0);
 
@@ -4943,7 +5088,7 @@
     if (StateIsLiveTV(mctx->GetState()))
         mctx->buffer->Unpause();
 
-    bool ok = StartPlayer(mctx, mctx, mctx->GetState(), false);
+    bool ok = StartPlayer(mctx, mctx, mctx->GetState());
 
     if (ok)
     {
@@ -4953,7 +5098,7 @@
     {
         VERBOSE(VB_IMPORTANT, loc +
                 "Failed to restart new main context (was pip context)");
-        ForceNextStateNone(mctx);
+        ForceNextStateNone(mctx, __LINE__);
         return;
     }
 
@@ -4966,7 +5111,7 @@
         if (StateIsLiveTV(pipctx->GetState()))
             pipctx->buffer->Unpause();
 
-        ok = StartPlayer(mctx, pipctx, pipctx->GetState(), pipctx->isPIP());
+        ok = StartPlayer(mctx, pipctx, pipctx->GetState());
 
         if (ok)
         {
@@ -4978,7 +5123,7 @@
         { // TODO print OSD informing user of Swap failure ?
             VERBOSE(VB_IMPORTANT, loc +
                     "Failed to restart new pip context (was main context)");
-            ForceNextStateNone(pipctx);
+            ForceNextStateNone(pipctx, __LINE__);
         }
     }
 
@@ -4988,15 +5133,17 @@
         mctx->nvp->SetMuteState(mctx_mute);
 }
 
-void TV::SwapPIP(PlayerContext *lctx, int ctx_index, bool ispbp)
+void TV::PxPSwap(PlayerContext *mctx, int ctx_index)
 {
     lockTimerOn = false;
 
-    PlayerContext *mctx = GetPlayer(lctx, 0);
-    if (player.size() == 1)
+    if (player.size() <= 1 || !mctx)
         return;
 
-    PlayerContext *pipctx = GetPlayer(lctx, ctx_index);
+    PlayerContext *pipctx = GetPlayer(mctx, ctx_index);
+    ctx_index = find_player_index(pipctx);
+    if (ctx_index < 0 || !pipctx)
+        return;
 
     if (!mctx->nvp || !pipctx->nvp || !pipctx->nvp->IsPlaying())
         return;
@@ -5004,31 +5151,20 @@
     VERBOSE(VB_PLAYBACK, LOC + "SwapPIP -- begin");
 
     MuteState mctx_mute = mctx->nvp->GetMuteState();
-
-    vector<long long> pos;
-    for (uint i = 0; i < player.size(); i++)
-    {
-        const PlayerContext *ctx = GetPlayer(lctx, i);
-        ctx->LockDeleteNVP(__FILE__, __LINE__);
-        pos.push_back((ctx->nvp) ? ctx->nvp->GetFramesPlayed() : 0);
-        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
-    }
-
     bool useNullVideo = pipctx->UseNullVideo();
 
-    TeardownPIPWindows(lctx);
+    vector<long long> pos = TeardownAllNVPs(mctx);
 
-    swap(player[0], player[ctx_index]);
-    swap(pos[0],    pos[ctx_index]);
-
-    pipctx->SetPIPState((ispbp) ? kPBPLeft: kPIPOff);
-
+    swap(player[0],           player[ctx_index]);
+    swap(pos[0],              pos[ctx_index]);
+    swap(player[0]->pipState, player[ctx_index]->pipState);
+    playerActive = (ctx_index == playerActive) ?
+        0 : ((ctx_index == 0) ? ctx_index : playerActive);
+    
     if (useNullVideo)
         mctx->SetNullVideo(true);
 
-    mctx->SetPIPState((ispbp) ? kPBPRight: kPIPonTV);
-
-    RestartPIPWindows(mctx, pos, mctx_mute);
+    RestartAllNVPs(mctx, pos, mctx_mute);
 }
 
 void TV::DoPlay(PlayerContext *ctx)
@@ -5387,7 +5523,7 @@
             ctx->playingInfo->ApplyTranscoderProfileChange(profile);
             QString jobHost = "";
 
-            if (gContext->GetNumSetting("JobsRunOnRecordHost", 0))
+            if (db_run_jobs_on_remote)
                 jobHost = ctx->playingInfo->hostname;
 
             OSD *osd = GetOSDLock(ctx);
@@ -5598,8 +5734,11 @@
 
     if (testrec && testrec->IsValidRecorder())
     {
-        // pause the decoder first, so we're not reading to close to the end.
+        PlayerContext *mctx = GetPlayer(ctx, 0);
+        if (mctx != ctx)
+            PIPRemovePlayer(mctx, ctx);
 
+        // pause the decoder first, so we're not reading too close to the end.
         ctx->buffer->IgnoreLiveEOF(true);
         ctx->buffer->StopReads();
         ctx->nvp->PauseDecoder();
@@ -5609,12 +5748,7 @@
         ctx->buffer->WaitForPause();
         ctx->nvp->StopPlaying();
         ctx->recorder->StopLiveTV();
-        {
-            ctx->SetNVP(NULL);
-            PlayerContext *mctx = GetPlayer(ctx, 0);
-            if (ctx != mctx)
-                SetPIPPlayer(mctx, ctx);
-        }
+        ctx->SetNVP(NULL);
 
         // now restart stuff
         ctx->lastSignalUIInfo.clear();
@@ -5658,19 +5792,8 @@
                 ok = true;
                 ctx->StartOSD(this);
                 ctx->PushPreviousChannel();
-                if (ctx && (player.size() > 1))
-                {
-                    if (0 == playerActive)
-                    {
-                        PlayerContext *ctx1 = GetPlayer(ctx, 1);
-                        SetPIPPlayer(mctx, ctx1);
-                    }
-                    else
-                    {
-                        PlayerContext *mctx = GetPlayer(ctx, 0);
-                        SetPIPPlayer(mctx, ctx);
-                    }
-                }
+                for (uint i = 1; i < player.size(); i++)
+                    PIPAddPlayer(mctx, GetPlayer(ctx, i));
 
                 SetSpeedChangeTimer(25, __LINE__);
             }
@@ -6957,11 +7080,8 @@
     margin = margin * 5;
     QDomElement xmldata;
     XMLParse *theme = new XMLParse();
-    if (!allowembed ||
-        !theme->LoadTheme(xmldata, str) ||
-        !gContext->GetNumSetting("ContinueEmbeddedTVPlay", 0) ||
-        ctx->nvp->IsNearEnd(margin) ||
-        ctx->paused)
+    if (!allowembed || !theme->LoadTheme(xmldata, str) ||
+        !db_continue_embedded || ctx->nvp->IsNearEnd(margin) || ctx->paused)
     {
         if (!stayPaused)
             DoPause(ctx, false);
@@ -6976,31 +7096,32 @@
 
 void TV::DoEditSchedule(int editType)
 {
-    PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
-    mctx->LockPlayingInfo(__FILE__, __LINE__);
-    if (!mctx->playingInfo)
+    PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
+
+    actx->LockPlayingInfo(__FILE__, __LINE__);
+    if (!actx->playingInfo)
     {
         VERBOSE(VB_IMPORTANT,
-                LOC_ERR + "doEditSchedule(): no active mctx->playingInfo.");
-        mctx->UnlockPlayingInfo(__FILE__, __LINE__);
-        ReturnPlayerLock(mctx);
+                LOC_ERR + "doEditSchedule(): no active ctx playingInfo.");
+        actx->UnlockPlayingInfo(__FILE__, __LINE__);
+        ReturnPlayerLock(actx);
         return;
     }
 
     // Collect channel info
-    uint    chanid  = mctx->playingInfo->chanid.toUInt();
-    QString channum = mctx->playingInfo->chanstr;
-    mctx->UnlockPlayingInfo(__FILE__, __LINE__);
+    uint    chanid  = actx->playingInfo->chanid.toUInt();
+    QString channum = actx->playingInfo->chanstr; channum.detach();
+    actx->UnlockPlayingInfo(__FILE__, __LINE__);
 
-    ClearOSD(mctx);
+    ClearOSD(actx);
 
     // Resize window to the MythTV GUI size
-
+    PlayerContext *mctx = GetPlayer(actx, 0);
     if (mctx->nvp && mctx->nvp->getVideoOutput()) 
         mctx->nvp->getVideoOutput()->ResizeForGui(); 
     MythMainWindow *mwnd = gContext->GetMainWindow();
-    bool using_gui_size_for_tv = gContext->GetNumSetting("GuiSizeForTV", 0);
-    if (!using_gui_size_for_tv)
+
+    if (!db_use_gui_size_for_tv)
     {
         mwnd->setGeometry(saved_gui_bounds.left(), saved_gui_bounds.top(),
                           saved_gui_bounds.width(), saved_gui_bounds.height());
@@ -7026,46 +7147,58 @@
                 player = this;
             if (StateIsLiveTV(GetState(mctx)))
             {
-                ReturnPlayerLock(mctx);
+                ReturnPlayerLock(actx);
                 changeChannel = GuideGrid::Run(chanid, channum, false,
                                                player, allowsecondary);
-                mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
+                actx = GetPlayerReadLock(0, __FILE__, __LINE__);
             }
             else
             {
-                ReturnPlayerLock(mctx);
+                ReturnPlayerLock(actx);
                 GuideGrid::Run(chanid, channum, false, player);
-                mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
+                actx = GetPlayerReadLock(0, __FILE__, __LINE__);
             }
             break;
         }
         case kScheduleProgramFinder:
             if (!mctx->paused)
                 DoPause(mctx, false);
+            ReturnPlayerLock(actx);
             RunProgramFind(false, false);
+            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
             break;
         case kScheduledRecording:
         {
             if (mctx->paused)
                 DoPause(mctx, false);
+
             mctx->LockPlayingInfo(__FILE__, __LINE__);
+            const ProgramInfo pginfo(*mctx->playingInfo);
+            mctx->UnlockPlayingInfo(__FILE__, __LINE__);
+            ReturnPlayerLock(actx);
+
             ScheduledRecording *record = new ScheduledRecording();
-            record->loadByProgram(mctx->playingInfo);
+            record->loadByProgram(&pginfo);
             record->exec();
             record->deleteLater();
-            mctx->UnlockPlayingInfo(__FILE__, __LINE__);
+
+            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
             break;
         }
         case kViewSchedule:
         {
             showvideo = VideoThemeCheck(mctx, "conflict-video", stayPaused);
+            ReturnPlayerLock(actx);
             RunViewScheduledPtr((void *)this, showvideo);
+            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
             break;
         }
         case kPlaybackBox:
         {
             showvideo = VideoThemeCheck(mctx, "playback-video", stayPaused);
+            ReturnPlayerLock(actx);
             nextProgram = RunPlaybackBoxPtr((void *)this, showvideo);
+            actx = GetPlayerReadLock(0, __FILE__, __LINE__);
         }
     }
 
@@ -7080,29 +7213,34 @@
         embedCheckTimerId = 0;
     }
 
-    if (StateIsPlaying(GetState(mctx)) && 
+    VERBOSE(VB_PLAYBACK, LOC 
+            <<"state: "<<StateToString(GetState(mctx))
+            <<"!stayPaused: "<<stayPaused<<" mctx->paused: "<<mctx->paused);
+    if ((StateIsPlaying(GetState(mctx)) || StateIsLiveTV(GetState(mctx))) &&
         !stayPaused && mctx->paused)
     {
+        VERBOSE(VB_PLAYBACK, LOC + "Unpausing video");
+        // this should unpause video..
         DoPause(mctx, true);
     }
-    ReturnPlayerLock(mctx);
+    ReturnPlayerLock(actx);
 
     mctx = GetPlayerWriteLock(0, __FILE__, __LINE__);
     if (nextProgram)
     {
-        if (nextProgPIPState == kPIPonTV)
+        if (jumpToProgramPIPState == kPIPonTV)
             CreatePIP(mctx, nextProgram);
-        else if (nextProgPIPState == kPBPLeft)
+        else if (jumpToProgramPIPState == kPBPLeft)
             CreatePBP(mctx, nextProgram);
         else
         {
-            setLastProgram(nextProgram);
+            SetLastProgram(nextProgram);
             jumpToProgram = true;
             SetExitPlayer(true, true);
         }
         mctx = GetPlayer(mctx, 0); // CreatePBP/PIP mess with ctx's
 
-        nextProgPIPState = kPIPOff;
+        jumpToProgramPIPState = kPIPOff;
         delete nextProgram;
         nextProgram = NULL;
     }
@@ -7110,7 +7248,7 @@
 
     mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
     // Resize the window back to the MythTV Player size
-    if (!using_gui_size_for_tv)
+    if (!db_use_gui_size_for_tv)
     {
         mwnd->setGeometry(player_bounds.left(), player_bounds.top(),
                           player_bounds.width(), player_bounds.height());
@@ -7132,9 +7270,6 @@
 
 void TV::EditSchedule(const PlayerContext *ctx, int editType)
 {
-    if (ctx && (player.size() > 1))
-        return;
-
     // post the request to the main UI thread
     // it will be caught in eventFilter and processed as CustomEvent
     // this will create the program guide window (widget)
@@ -7494,7 +7629,7 @@
                 {
                     ctx->nvp->SetWatchingRecording(false);
                     ctx->nvp->SetLength(filelen);
-                    ctx->ChangeState(kState_WatchingPreRecorded);
+                    ctx->ChangeState(kState_WatchingPreRecorded, __LINE__);
                     ScheduleStateChange(ctx);
                 }
             }
@@ -7644,17 +7779,15 @@
 
     if (message.left(12) == "EXIT_TO_MENU")
     {
-        int exitprompt = gContext->GetNumSetting("PlaybackExitPrompt");
-
         PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
         for (uint i = 0; mctx && (i < player.size()); i++)
         {
             PlayerContext *ctx = GetPlayer(mctx, i);
             if (!ctx->nvp)
                 continue;
-            if (exitprompt == 1 || exitprompt == 2)
+            if (db_playback_exit_prompt == 1 || db_playback_exit_prompt == 2)
                 ctx->nvp->SetBookmark();
-            if (ctx->nvp && gContext->GetNumSetting("AutomaticSetWatched", 0))
+            if (ctx->nvp && db_auto_set_watched)
                 ctx->nvp->SetWatched();
         }
 
@@ -7733,15 +7866,8 @@
         }
     }
 
-    int player_cnt = 0;
+    if (message.left(9) == "START_EPG")
     {
-        PlayerContext *mctx = GetPlayerReadLock(0, __FILE__, __LINE__);
-        player_cnt = player.size();
-        ReturnPlayerLock(mctx);
-    }
-
-    if (message.left(9) == "START_EPG" && (1 == player_cnt))
-    {
         int editType = tokens[1].toInt();
         DoEditSchedule(editType);
     }
@@ -7844,6 +7970,7 @@
         browsechannum   = ctx->playingInfo->chanstr;
         browsechanid    = ctx->playingInfo->chanid;
         browsestarttime = ctx->playingInfo->startts.toString();
+        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
 
         BrowseDispInfo(ctx, BROWSE_SAME);
 
@@ -7852,7 +7979,10 @@
             KillTimer(browseTimerId);
         browseTimerId = StartTimer(kBrowseTimeout, __LINE__);
     }
-    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
+    else
+    {
+        ctx->UnlockPlayingInfo(__FILE__, __LINE__);
+    }
 }
 
 /** \fn TV::BrowseEnd(PlayerContext*, bool)
@@ -7986,8 +8116,7 @@
     QString cmdmsg("");
     if (ctx->playingInfo->GetAutoExpireFromRecorded() == kLiveTVAutoExpire)
     {
-        int autoexpiredef = gContext->GetNumSetting("AutoExpireDefault", 0);
-        ctx->playingInfo->SetAutoExpire(autoexpiredef);
+        ctx->playingInfo->SetAutoExpire(db_autoexpire_default);
         ctx->playingInfo->ApplyRecordRecGroupChange("Default");
         cmdmsg = tr("Record");
         ctx->SetPseudoLiveTV(ctx->playingInfo, kPseudoRecording);
@@ -8155,38 +8284,51 @@
     SetUpdateOSDPosition(false);
 }
 
-void TV::SetActive(PlayerContext *ctx, int index)
+#include <cassert>
+void TV::SetActive(PlayerContext *lctx, int index, bool osd_msg)
 {
-    VERBOSE(VB_PLAYBACK, "TV::SetActive -- begin");
+    assert(lctx);
+    if (!lctx)
+        return;
 
+    QString loc = LOC + QString("SetActive(%1,%2) was %3")
+        .arg(index).arg((osd_msg) ? "with OSD" : "w/o OSD").arg(playerActive);
+
+    VERBOSE(VB_PLAYBACK, loc + " -- begin");
+
     if (playerActive == index)
     {
-        VERBOSE(VB_PLAYBACK, "TV::SetActive -- index == active context");
+        VERBOSE(VB_PLAYBACK, loc + " -- end (index == playerActive)");
         return;
     }
 
-    VERBOSE(VB_PLAYBACK, "TV::SetActive -- lock");
+    index = (index < 0) ? (playerActive+1) % player.size() : index;
+    index = (index >= (int)player.size()) ? 0 : index;
 
-    PlayerContext *actx = NULL;
+    playerActive = index;
 
-    if (playerActive > -1 && !ctx)
+    for (int i = 0; i < (int)player.size(); i++)
     {
-        actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
-        ReturnPlayerLock(actx);
+        PlayerContext *ctx = GetPlayer(lctx, i);
+        ctx->LockDeleteNVP(__FILE__, __LINE__);
+        if (ctx->nvp)
+            ctx->nvp->SetPIPActive(i == playerActive);
+        ctx->UnlockDeleteNVP(__FILE__, __LINE__);
     }
 
-    VERBOSE(VB_PLAYBACK,
-            QString("TV::SetActive changing playerActive "
-                    "from %1 to %2")
-                    .arg(playerActive).arg(index));
-
-    playerActive = index;
-
-    if (!ctx)
+#if 0
+    // seems reduntant, except maybe for main player? -dtk
+    if (osd_msg)
     {
-        actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
-        ReturnPlayerLock(actx);
+        PlayerContext *actx = GetPlayer(lctx, -1);
+        OSD *osd = GetOSDLock(actx);
+        if (osd)
+            osd->SetSettingsText(tr("Active").arg(playerActive), 3);
+        ReturnOSDLock(actx, osd);
     }
+#endif
+
+    VERBOSE(VB_PLAYBACK, loc + " -- end");
 }
 
 void TV::TreeMenuEntered(OSDListTreeType *tree, OSDGenericTree *item)
@@ -8733,63 +8875,26 @@
         EditSchedule(actx, kScheduleProgramFinder);
     else if (action == "SCHEDULE")
         EditSchedule(actx, kScheduledRecording);
-    else if ((action == "JUMPPREV") ||
-             ((action == "PREVCHAN") && (!StateIsLiveTV(GetState(actx)))))
-    {
-        if (PromptRecGroupPassword(actx))
-        {
-            actx->nvp->SetBookmark();
-            jumpToProgram = true;
-            SetExitPlayer(true, true);
-        }
-    }
     else if (action == "VIEWSCHEDULED")
         EditSchedule(actx, kViewSchedule);
-    else if (action == "JUMPREC")
+    else if (HandleJumpToProgramAction(actx, QStringList(action)))
     {
-        if (gContext->GetNumSetting("JumpToProgramOSD", 1) &&
-            StateIsPlaying(actx->GetState()))
-        {
-            if (jumpMenuTimerId)
-                KillTimer(jumpMenuTimerId);
-            jumpMenuTimerId = StartTimer(1, __LINE__);
-        }
-        else if (RunPlaybackBoxPtr)
-            EditSchedule(actx, kPlaybackBox);
     }
-    else if (action == "TOGGLEPIPMODE")
+    else if (PxPHandleAction(actx, QStringList(action)))
     {
-        ReturnPlayerLock(actx);
+        // Hide the tree on this old active context..
+        tree->SetVisible(false);
+        tree->disconnect();
+        OSD *osd = GetOSDLock(actx);
+        if (osd)
+            osd->HideTreeMenu();
+        ReturnOSDLock(actx, osd);
+        ClearOSD(actx);
 
-        actx = GetPlayerWriteLock(-1, __FILE__, __LINE__);
-        TogglePIPView(actx);
-        ReturnPlayerLock(actx);
+        hidetree = true;
 
-        actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
+        actx = GetPlayer(actx,-1); // "NEXTPIPWINDOW" changes active context..
     }
-    else if (action == "TOGGLEPBPMODE")
-    {
-        needToMakePIPChange = kPBPToggle;
-        if (pipChangeTimerId)
-            KillTimer(pipChangeTimerId);
-        pipChangeTimerId = StartTimer(1, __LINE__);
-    }
-    else if (action == "TOGGLEPIPWINDOW")
-        ToggleActiveWindow(actx, 1);
-    else if (action == "TOGGLEPIPSTATE")
-    {
-        needToMakePIPChange = (actx->isPBP()) ? kPBPToPIP : kPIPToPBP;
-        if (pipChangeTimerId)
-            KillTimer(pipChangeTimerId);
-        pipChangeTimerId = StartTimer(1, __LINE__);
-    }
-    else if (action == "SWAPPIP")
-    {
-        needToMakePIPChange = (actx->isPBP()) ? kPBPSwap : kPIPSwap;
-        if (pipChangeTimerId)
-            KillTimer(pipChangeTimerId);
-        pipChangeTimerId = StartTimer(1, __LINE__);
-    }
     else if (StateIsLiveTV(GetState(actx)))
     {
         if (action == "TOGGLEBROWSE")
@@ -8833,14 +8938,6 @@
             DoQueueTranscode(actx, "Medium Quality");
         else if (action == "QUEUETRANSCODE_LOW")
             DoQueueTranscode(actx, "Low Quality");
-        else if (action.left(8) == "JUMPPROG")
-        {
-            SetJumpToProgram(action.section(" ",1,-2),
-                             action.section(" ",-1,-1).toInt());
-            actx->nvp->SetBookmark();
-            jumpToProgram = true;
-            SetExitPlayer(true, true);
-        }
         else
         {
             VERBOSE(VB_IMPORTANT, LOC_ERR +
@@ -8901,39 +8998,9 @@
         delete treeMenu;
 
     treeMenu = new OSDGenericTree(NULL, "treeMenu");
-    OSDGenericTree *item, *subitem;
 
     bool freeRecorders = RemoteGetFreeRecorderCount();
 
-    if (IsPIPSupported(ctx) && ((ctx && (player.size() > 1)) || freeRecorders))
-    {
-        // Picture-in-Picture
-        item = new OSDGenericTree(treeMenu, tr("Picture-in-Picture"));
-        if (ctx && (player.size() == 1))
-        {
-            subitem = new OSDGenericTree(item, tr("Enable PIP"),
-                                         "TOGGLEPIPMODE");
-            subitem = new OSDGenericTree(item, tr("Enable PBP"),
-                                         "TOGGLEPBPMODE");
-        }
-        else
-        {
-            QString option = "Disable ";
-            QString switchTo = "Switch to ";
-            QString pipType = (ctx->isPBP()) ? "PBP" : "PIP";
-            QString changeTo = (ctx->isPBP()) ? "PIP" : "PBP";
-            option += pipType;
-            switchTo += changeTo;
-            QString toggleMode = QString("TOGGLE%1MODE").arg(pipType);
-            subitem = new OSDGenericTree(item, option, toggleMode);
-            subitem = new OSDGenericTree(item, tr("Swap Windows"), 
-                                         "SWAPPIP");
-            subitem = new OSDGenericTree(item, tr("Change Active Window"),
-                                         "TOGGLEPIPWINDOW");
-            subitem = new OSDGenericTree(item, switchTo, "TOGGLEPIPSTATE");
-        }
-    }
-
     if (freeRecorders && ctx->recorder)
     {
         // Input switching
@@ -9011,6 +9078,8 @@
         }
     }
 
+    FillMenuPxP(ctx, treeMenu, freeRecorders);
+
     if ((ctx != GetPlayer(ctx, 0)))
         return;
 
@@ -9161,19 +9230,78 @@
     new OSDGenericTree(s_item, "120 " + tr("minutes"), "TOGGLESLEEP120");
 }
 
-void TV::FillMenuLiveTV(OSDGenericTree *treeMenu)
+/// \brief Constructs Picture-X-Picture portion of menu
+void TV::FillMenuPxP(
+    const PlayerContext *ctx, OSDGenericTree *treeMenu, bool freeRecorders)
 {
-    new OSDGenericTree(treeMenu, tr("Program Guide"), "GUIDE");
+    if (!ctx || !IsPIPSupported(ctx))
+        return;
 
-    if (!gContext->GetNumSetting("JumpToProgramOSD", 1))
+    if ((player.size() <= 1) && !freeRecorders)
+        return;
+
+    OSDGenericTree *item =
+        new OSDGenericTree(treeMenu, tr("Picture-in-Picture"));
+
+    if (freeRecorders)
     {
-        OSDGenericTree *jtpo_item =
-            new OSDGenericTree(treeMenu, tr("Jump to Program"));
-        new OSDGenericTree(jtpo_item, tr("Recorded Program"), "JUMPREC");
-        if (lastProgram != NULL)
-            new OSDGenericTree(jtpo_item, lastProgram->title, "JUMPPREV");
+        if (player.size() <= kMaxPIPCount)
+            new OSDGenericTree(item, tr("Open Live TV PIP"), "CREATEPIPVIEW");
+        if (player.size() <= kMaxPBPCount)
+            new OSDGenericTree(item, tr("Open Live TV PBP"), "CREATEPBPVIEW");
     }
 
+    if (player.size() <= kMaxPIPCount)
+        new OSDGenericTree(item, tr("Open Recording PIP"), "JUMPRECPIP");
+    if (player.size() <= kMaxPBPCount)
+        new OSDGenericTree(item, tr("Open Recording PBP"), "JUMPRECPBP");
+
+    if (player.size() <= 1)
+        return;
+
+    new OSDGenericTree(item, tr("Change Active Window"), "NEXTPIPWINDOW");
+
+    QString pipType  = (ctx->isPBP()) ? "PBP" : "PIP";
+    QString toggleMode = QString("TOGGLE%1MODE").arg(pipType);
+
+    bool isPBP = ctx->isPBP();
+    const PlayerContext *mctx = GetPlayer(ctx, 0);
+    QString pipClose = (isPBP) ? tr("Close PBP") : tr("Close PIP");
+    if (mctx == ctx)
+    {
+        if (player.size() > 2)
+            pipClose = (isPBP) ? tr("Close PBPs") : tr("Close PIPs");
+
+        new OSDGenericTree(item, pipClose, toggleMode);
+
+        if (player.size() == 2)
+            new OSDGenericTree(item, tr("Swap Windows"), "SWAPPIP");
+    }
+    else
+    {
+        new OSDGenericTree(item, pipClose, toggleMode);
+        new OSDGenericTree(item, tr("Swap Windows"), "SWAPPIP");
+    }
+
+    uint max_cnt = min(kMaxPBPCount, kMaxPIPCount);
+    if (player.size() <= max_cnt)
+    {
+        QString switchTo = (isPBP) ? tr("Switch to PIP") : tr("Switch to PBP");
+        new OSDGenericTree(item, switchTo, "TOGGLEPIPSTATE");
+    }
+}
+
+
+void TV::FillMenuLiveTV(OSDGenericTree *treeMenu)
+{
+    new OSDGenericTree(treeMenu, tr("Program Guide"), "GUIDE");
+
+    OSDGenericTree *jtpo_item =
+        new OSDGenericTree(treeMenu, tr("Jump to Program"));
+    new OSDGenericTree(jtpo_item, tr("Recorded Program"), "JUMPREC");
+    if (lastProgram != NULL)
+        new OSDGenericTree(jtpo_item, lastProgram->title, "JUMPPREV");
+
     if (!persistentbrowsemode)
         new OSDGenericTree(treeMenu, tr("Enable Browse Mode"), "TOGGLEBROWSE");
 
@@ -9403,15 +9531,136 @@
     ReturnOSDLock(ctx, osd);
 }
 
-void TV::SetJumpToProgram(QString progKey, int progIndex)
+bool TV::HandleJumpToProgramAction(
+    PlayerContext *ctx, const QStringList &actions)
 {
-    QMap<QString,ProgramList>::Iterator Iprog;
-    Iprog = progLists.find(progKey);
-    ProgramList plist = *Iprog;
-    ProgramInfo *p = plist.at(progIndex);
-    VERBOSE(VB_IMPORTANT, QString("Switching to program: %1: %2")
-            .arg(p->title).arg(p->subtitle));
-    setLastProgram(p);
+    const PlayerContext *mctx = GetPlayer(ctx, 0);
+    TVState s = ctx->GetState();
+    if (has_action("JUMPPREV", actions) ||
+        (has_action("PREVCHAN", actions) && !StateIsLiveTV(s)))
+    {
+        if (PromptRecGroupPassword(ctx))
+        {
+            if (mctx == ctx)
+            {
+                ctx->LockDeleteNVP(__FILE__, __LINE__);
+                ctx->nvp->SetBookmark();
+                ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+                jumpToProgram = true;
+                SetExitPlayer(true, true);
+            }
+            else
+            {
+                // TODO
+            }
+        }
+        return true;
+    }
+
+    QStringList::const_iterator it = actions.begin();
+    for (; it != actions.end(); ++it)
+    {
+        if ((*it).left(8) != "JUMPPROG")
+            continue;
+
+        const QString &action = *it;
+
+        bool ok;
+        QString progKey   = action.section(" ",1,-2);
+        uint    progIndex = action.section(" ",-1,-1).toUInt(&ok);
+        ProgramInfo *p = NULL;
+
+        if (!ok)
+        {
+            QMutexLocker locker(&progListsLock);
+            QMap<QString,ProgramList>::const_iterator it =
+                progLists.find(progKey);
+            if (it != progLists.end())
+            {
+                const ProgramInfo *tmp = (*it)[progIndex];
+                if (tmp)
+                    p = new ProgramInfo(*tmp);
+            }
+        }
+
+        if (!p)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR +
+                    QString("Failed to locate jump to program '%1' @ %2")
+                    .arg(progKey).arg(action.section(" ",-1,-1).toUInt(&ok)));
+            return true;
+        }
+
+        PIPState state = kPIPOff;
+        {
+            QMutexLocker locker(&timerIdLock);
+            state = jumpToProgramPIPState;
+        }
+
+        if (kPIPOff == state)
+        {
+            if (mctx == ctx)
+            {
+                VERBOSE(VB_GENERAL, LOC +
+                        QString("Switching to program: %1: %2")
+                        .arg(p->title).arg(p->subtitle));
+            
+                SetLastProgram(p);
+                ctx->LockDeleteNVP(__FILE__, __LINE__);
+                ctx->nvp->SetBookmark();
+                ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+                jumpToProgram = true;
+                SetExitPlayer(true, true);
+            }
+            else
+            {
+                // TODO
+            }
+        }
+        else
+        {
+            QString type = (kPIPonTV == jumpToProgramPIPState) ? "PIP" : "PBP";
+            VERBOSE(VB_GENERAL, LOC + QString("Creating %1 with program: %2: %3")
+                    .arg(type).arg(p->title).arg(p->subtitle));
+
+            if (jumpToProgramPIPState == kPIPonTV)
+                CreatePIP(ctx, p);
+            else if (jumpToProgramPIPState == kPBPLeft)
+                CreatePBP(ctx, p);
+        }
+
+        delete p;
+
+        return true;
+    }
+
+    bool wants_jump = has_action("JUMPREC", actions);
+    bool wants_pip = !wants_jump && has_action("JUMPRECPIP", actions);
+    bool wants_pbp = !wants_jump && !wants_pip &&
+        has_action("JUMPRECPBP", actions);
+
+    if (!wants_jump && !wants_pip && !wants_pbp)
+        return false;
+
+    {
+        QMutexLocker locker(&timerIdLock);
+        jumpToProgramPIPState = wants_pip ? kPIPonTV :
+            (wants_pbp ? kPBPLeft : kPIPOff);
+    }
+
+    if (db_jump_prefer_osd && (StateIsPlaying(s) || StateIsLiveTV(s)))
+    {
+        QMutexLocker locker(&timerIdLock);
+        if (jumpMenuTimerId)
+            KillTimer(jumpMenuTimerId);
+        jumpMenuTimerId = StartTimer(1, __LINE__);
+    }
+    else if (RunPlaybackBoxPtr)
+        EditSchedule(ctx, kPlaybackBox);
+    else
+        VERBOSE(VB_IMPORTANT, "Failed to open jump to program GUI");
+
+    return true;
 }
 
 void TV::ToggleSleepTimer(const PlayerContext *ctx, const QString &time)
@@ -9769,13 +10018,8 @@
 
     ctx->UnlockPlayingInfo(__FILE__, __LINE__);
 
-    if (isDVD && (!gContext->GetNumSetting("EnableDVDBookmark", 0) ||
-                  ctx->buffer->DVD()->GetTotalTimeOfTitle() < 120))
-    {
-        return false;
-    }
-
-    return true;
+    return (!isDVD || (db_use_dvd_bookmark &&
+                       ctx->buffer->DVD()->GetTotalTimeOfTitle() >= 120));
 }
 
 /* \fn TV::IsDeleteAllowed(const PlayerContext*) const
@@ -9917,8 +10161,10 @@
             dialogname == "exitplayoptions");
 }
 
-void TV::setLastProgram(ProgramInfo *rcinfo)
+void TV::SetLastProgram(ProgramInfo *rcinfo)
 {
+    QMutexLocker locker(&lastProgramLock);
+
     if (lastProgram)
         delete lastProgram;
 
@@ -9928,6 +10174,14 @@
         lastProgram = NULL;
 }
 
+ProgramInfo *TV::GetLastProgram(void) const
+{
+    QMutexLocker locker(&lastProgramLock);
+    if (lastProgram)
+        return new ProgramInfo(*lastProgram);
+    return NULL;
+}
+
 QString TV::GetRecordingGroup(int player_idx) const
 {
     QString ret = QString::null;
@@ -10022,31 +10276,29 @@
     treeMenu = new OSDGenericTree(NULL, "treeMenu");
 
     // Build jumpMenu of recorded program titles
-    ProgramInfo *p;
+    QMutexLocker locker(&progListsLock);
     progLists.clear();
-    vector<ProgramInfo *> *infoList;
-    infoList = RemoteGetRecordedList(false);
+    vector<ProgramInfo *> *infoList = RemoteGetRecordedList(false);
 
     //bool LiveTVInAllPrograms = gContext->GetNumSetting("LiveTVInAllPrograms",0);
     if (infoList)
     {
         PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
         actx->LockPlayingInfo(__FILE__, __LINE__);
-        vector<ProgramInfo *>::iterator i = infoList->begin();
-        for ( ; i != infoList->end(); i++)
+        vector<ProgramInfo *>::const_iterator it = infoList->begin();
+        for ( ; it != infoList->end(); it++)
         {
-            p = *i;
             //if (p->recgroup != "LiveTV" || LiveTVInAllPrograms)
-            if (p->recgroup == actx->playingInfo->recgroup)
-                progLists[p->title].prepend(p); 
+            if ((*it)->recgroup == actx->playingInfo->recgroup)
+                progLists[(*it)->title].push_front(new ProgramInfo(*(*it)));
         }
         actx->UnlockPlayingInfo(__FILE__, __LINE__);
         ReturnPlayerLock(actx);
 
-        QMap<QString,ProgramList>::Iterator Iprog; 
+        QMap<QString,ProgramList>::const_iterator Iprog; 
         for (Iprog = progLists.begin(); Iprog != progLists.end(); Iprog++)
         {
-            ProgramList plist = *Iprog;
+            const ProgramList &plist = *Iprog;
             int progIndex = plist.count();
             if (progIndex == 1)
             {
@@ -10061,8 +10313,8 @@
 
                 for (int i = 0; i < progIndex; i++)
                 {
-                    p = plist.at(i);
-                    if (p->subtitle.size())
+                    const ProgramInfo *p = plist[i];
+                    if (!p->subtitle.isEmpty())
                         new OSDGenericTree(j_item, p->subtitle,
                             QString("JUMPPROG %1 %2").arg(Iprog.key()).arg(i));
                     else
@@ -10072,6 +10324,12 @@
             }
         }
     }
+    while (!infoList->empty())
+    {
+        delete infoList->back();
+        infoList->pop_back();
+    }
+    delete infoList;
 
     PlayerContext *actx = GetPlayerReadLock(-1, __FILE__, __LINE__);
     OSD *osd = GetOSDLock(actx);
@@ -10093,7 +10351,7 @@
         }
     }
     ReturnOSDLock(actx, osd);
-
+    ReturnPlayerLock(actx);
 }
 
 void TV::RestoreScreenSaver(const PlayerContext *ctx)
@@ -10104,10 +10362,9 @@
 
 void TV::InitUDPNotifyEvent(void)
 {
-    uint udp_port = gContext->GetNumSetting("UDPNotifyPort");
-    if (udp_port && !udpnotify)
+    if (db_udpnotify_port && !udpnotify)
     {
-        udpnotify = new UDPNotify(udp_port);
+        udpnotify = new UDPNotify(db_udpnotify_port);
         connect(udpnotify,
                 SIGNAL(AddUDPNotifyEvent(
                         const QString&,const UDPNotifyOSDSet*)),
@@ -10242,6 +10499,10 @@
 {
     playerLock.lockForWrite();
 
+    //VERBOSE(VB_IMPORTANT, LOC_WARN +
+    //        QString("GetPlayerWriteLock(%1,%2,%3) size(%4)")
+    //        .arg(which).arg(file).arg(location).arg(player.size()));
+
     if ((which >= (int)player.size()))
     {
         VERBOSE(VB_IMPORTANT, LOC_WARN +
@@ -10257,6 +10518,10 @@
 {
     playerLock.lockForRead();
 
+    //VERBOSE(VB_IMPORTANT, LOC_WARN +
+    //        QString("GetPlayerReadLock(%1,%2,%3) size(%4)")
+    //        .arg(which).arg(file).arg(location).arg(player.size()));
+
     if ((which >= (int)player.size()))
     {
         VERBOSE(VB_IMPORTANT, LOC_WARN +
@@ -10273,6 +10538,10 @@
 {
     playerLock.lockForRead();
 
+    //VERBOSE(VB_IMPORTANT, LOC_WARN +
+    //        QString("GetPlayerReadLock(%1,%2,%3) const size(%4)")
+    //        .arg(which).arg(file).arg(location).arg(player.size()));
+
     if ((which >= (int)player.size()))
     {
         VERBOSE(VB_IMPORTANT, LOC_WARN +
@@ -10320,12 +10589,20 @@
 
 void TV::ReturnPlayerLock(PlayerContext *&ctx)
 {
+    //VERBOSE(VB_IMPORTANT, LOC_WARN +
+    //        QString("ReturnPlayerLock() size(%4)")
+    //        .arg(player.size()));
+
     playerLock.unlock();
     ctx = NULL;
 }
 
 void TV::ReturnPlayerLock(const PlayerContext *&ctx) const
 {
+    //VERBOSE(VB_IMPORTANT, LOC_WARN +
+    //        QString("ReturnPlayerLock() const size(%4)")
+    //        .arg(player.size()));
+
     playerLock.unlock();
     ctx = NULL;
 }
Index: libs/libmythtv/videoout_null.cpp
===================================================================
--- libs/libmythtv/videoout_null.cpp	(revision 19373)
+++ libs/libmythtv/videoout_null.cpp	(working copy)
@@ -217,10 +217,10 @@
 
 void VideoOutputNull::ProcessFrame(VideoFrame *frame, OSD *osd,
                                    FilterChain *filterList,
-                                   NuppelVideoPlayer *pipPlayer)
+                                   const PIPMap &pipPlayers)
 {
     (void)frame;
     (void)osd;
     (void)filterList;
-    (void)pipPlayer;
+    (void)pipPlayers;
 }
Index: libs/libmythtv/videoouttypes.h
===================================================================
--- libs/libmythtv/videoouttypes.h	(revision 19373)
+++ libs/libmythtv/videoouttypes.h	(working copy)
@@ -11,13 +11,8 @@
     kPIPOff = 0,
     kPIPonTV,
     kPIPStandAlone,
-    kPIPSwap,
     kPBPLeft,
     kPBPRight,
-    kPBPSwap,
-    kPIPToPBP,
-    kPBPToPIP,
-    kPBPToggle
 } PIPState;
 
 typedef enum PIPLocation
Index: libs/libmythtv/videooutbase.cpp
===================================================================
--- libs/libmythtv/videooutbase.cpp	(revision 19373)
+++ libs/libmythtv/videooutbase.cpp	(working copy)
@@ -267,7 +267,7 @@
     pip_desired_display_size(160,128),  pip_display_size(0,0),
     pip_video_size(0,0),
     pip_tmp_buf(NULL),                  pip_tmp_buf2(NULL),
-    pip_scaling_context(NULL),          pad_pip_window(false),
+    pip_scaling_context(NULL),
 
     // Video resizing (for ITV)
     vsz_enabled(false),
@@ -788,8 +788,8 @@
 /*
  * \brief Determines PIP Window size and Position.
  */
-QRect VideoOutput::GetPIPRect(int location, 
-                    NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
+QRect VideoOutput::GetPIPRect(
+    PIPLocation location, NuppelVideoPlayer *pipplayer, bool do_pixel_adj) const
 {
     return windows[0].GetPIPRect(location, pipplayer, do_pixel_adj);
 }
@@ -799,7 +799,7 @@
  * \brief Sets up Picture in Picture image resampler.
  * \param pipwidth  input width
  * \param pipheight input height
- * \sa ShutdownPipResize(), ShowPIP(VideoFrame*,NuppelVideoPlayer*)
+ * \sa ShutdownPipResize(), ShowPIPs(VideoFrame*,const PIPMap&)
  */
 void VideoOutput::DoPipResize(int pipwidth, int pipheight)
 {
@@ -825,7 +825,7 @@
  * \fn VideoOutput::ShutdownPipResize()
  * \brief Shuts down Picture in Picture image resampler.
  * \sa VideoOutput::DoPipResize(int,int),
- *     ShowPIP(VideoFrame*,NuppelVideoPlayer*)
+ *     ShowPIPs(VideoFrame*,const PIPMap&)
  */
 void VideoOutput::ShutdownPipResize(void)
 {
@@ -851,34 +851,47 @@
     pip_display_size = QSize(0,0);
 }
 
+void VideoOutput::ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers)
+{
+    PIPMap::const_iterator it = pipPlayers.begin();
+    for (; it != pipPlayers.end(); ++it)
+        ShowPIP(frame, it.key(), *it);
+}
+
 /**
- * \fn VideoOutput::ShowPIP(VideoFrame*,NuppelVideoPlayer*)
+ * \fn VideoOutput::ShowPIP(VideoFrame*,NuppelVideoPlayer*,PIPLocation)
  * \brief Composites PiP image onto a video frame.
- * Note: This only works with memory backed VideoFrames,
- *       that is not XvMC.
+ *
+ *  Note: This only works with memory backed VideoFrames,
+ *        that is not XvMC, OpenGL, VDPAU, etc.
+ *
  * \param frame     Frame to composite PiP onto.
  * \param pipplayer Picture-in-Picture NVP.
+ * \param loc       Location of this PiP on the frame.
  */
-void VideoOutput::ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
+void VideoOutput::ShowPIP(VideoFrame        *frame,
+                          NuppelVideoPlayer *pipplayer,
+                          PIPLocation        loc)
 {
     if (!pipplayer)
         return;
 
-    int pipw, piph;
-
-    const float video_aspect = windows[0].GetVideoAspect();
+    const float video_aspect           = windows[0].GetVideoAspect();
+    const QRect display_video_rect     = windows[0].GetDisplayVideoRect();
+    const QRect video_rect             = windows[0].GetVideoRect();
+    const QRect display_visible_rect   = windows[0].GetDisplayVisibleRect();
+    const float overriden_video_aspect = windows[0].GetOverridenVideoAspect();
+    const QSize video_disp_dim         = windows[0].GetVideoDispDim();
+    const int   pip_size               = windows[0].GetPIPSize();
     const AspectOverrideMode aspectoverride = windows[0].GetAspectOverride();
-    const QRect display_video_rect = windows[0].GetDisplayVideoRect();
-    const QRect video_rect = windows[0].GetVideoRect();
-    const QRect display_visible_rect = windows[0].GetDisplayVisibleRect();
-    const float overriden_video_aspect = windows[0].GetOverridenVideoAspect();
-    const QSize video_disp_dim = windows[0].GetVideoDispDim();
 
-    VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
-    float pipVideoAspect = pipplayer->GetVideoAspect();
-    QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
-    uint  pipVideoWidth  = pipVideoDim.width();
-    uint  pipVideoHeight = pipVideoDim.height();
+    int pipw, piph;
+    VideoFrame *pipimage       = pipplayer->GetCurrentFrame(pipw, piph);
+    const bool  pipActive      = pipplayer->IsPIPActive();
+    const float pipVideoAspect = pipplayer->GetVideoAspect();
+    const QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
+    const uint  pipVideoWidth  = pipVideoDim.width();
+    const uint  pipVideoHeight = pipVideoDim.height();
 
     // If PiP is not initialized to values we like, silently ignore the frame.
     if ((video_aspect <= 0) || (pipVideoAspect <= 0) || 
@@ -890,7 +903,7 @@
     }
 
     // set height
-    int tmph = (int) ((frame->height * windows[0].GetPIPSize()) * 0.01f);
+    int tmph = (int) ((frame->height * pip_size) * 0.01f);
     pip_desired_display_size.setHeight((tmph >> 1) << 1);
 
     // adjust for letterbox modes...
@@ -944,7 +957,7 @@
 
             img_resample(pip_scaling_context, &img_out, &img_in);
           
-            if (pad_pip_window)
+            if (pipActive)
             {
                 AVPicture img_padded;
                 avpicture_fill(
@@ -952,48 +965,51 @@
                     pip_display_size.width(), pip_display_size.height());
 
                 int color[3] = { 20, 0, 200 }; //deep red YUV format
-                av_picture_pad(&img_padded, &img_out, pip_display_size.height(),
-                        pip_display_size.width(), PIX_FMT_YUV420P, 10, 10,
-                        10, 10, color);
+                av_picture_pad(&img_padded, &img_out,
+                               pip_display_size.height(),
+                               pip_display_size.width(),
+                               PIX_FMT_YUV420P, 10, 10, 10, 10, color);
                 
                 pipbuf = pip_tmp_buf2;
             }
             else
+            {
                 pipbuf = pip_tmp_buf;
+            }
 
             pipw = pip_display_size.width();
             piph = pip_display_size.height();
 
             init(&pip_tmp_image,
-                    FMT_YV12,
-                    pipbuf,
-                    pipw, piph,
-                    pipimage->bpp, sizeof(pipbuf));
+                 FMT_YV12,
+                 pipbuf,
+                 pipw, piph,
+                 pipimage->bpp, sizeof(pipbuf));
         }
     }
 
     // Figure out where to put the Picture-in-Picture window
     int xoff = 0;
     int yoff = 0;
-    switch (windows[0].GetPIPLocation())
+    switch (loc)
     {
         case kPIP_END:
         case kPIPTopLeft:
-                xoff = 30 + letterXadj;
-                yoff = 40 + letterYadj;
-                break;
+            xoff = 30 + letterXadj;
+            yoff = 40 + letterYadj;
+            break;
         case kPIPBottomLeft:
-                xoff = 30 + letterXadj;
-                yoff = frame->height - piph - 40 - letterYadj;
-                break;
+            xoff = 30 + letterXadj;
+            yoff = frame->height - piph - 40 - letterYadj;
+            break;
         case kPIPTopRight:
-                xoff = frame->width  - pipw - 30 - letterXadj;
-                yoff = 40 + letterYadj;
-                break;
+            xoff = frame->width  - pipw - 30 - letterXadj;
+            yoff = 40 + letterYadj;
+            break;
         case kPIPBottomRight:
-                xoff = frame->width  - pipw - 30 - letterXadj;
-                yoff = frame->height - piph - 40 - letterYadj;
-                break;
+            xoff = frame->width  - pipw - 30 - letterXadj;
+            yoff = frame->height - piph - 40 - letterYadj;
+            break;
     }
 
     uint xoff2[3]  = { xoff, xoff>>1, xoff>>1 };
@@ -1006,9 +1022,9 @@
         for (uint h = 2; h < height[p]; h++)
         {
             memcpy((frame->buf + frame->offsets[p]) + (h + yoff2[p]) * 
-                    frame->pitches[p] + xoff2[p],
-                    (pip_tmp_image.buf + pip_tmp_image.offsets[p]) + h *
-                    pip_tmp_image.pitches[p], pip_tmp_image.pitches[p]);
+                   frame->pitches[p] + xoff2[p],
+                   (pip_tmp_image.buf + pip_tmp_image.offsets[p]) + h *
+                   pip_tmp_image.pitches[p], pip_tmp_image.pitches[p]);
         }
     }
 
@@ -1020,7 +1036,7 @@
  * \brief Sets up Picture in Picture image resampler.
  * \param inDim  input width and height
  * \param outDim output width and height
- * \sa ShutdownPipResize(), ShowPIP(VideoFrame*,NuppelVideoPlayer*)
+ * \sa ShutdownPipResize(), ShowPIPs(VideoFrame*,const PIPMap&)
  */
 void VideoOutput::DoVideoResize(const QSize &inDim, const QSize &outDim)
 {
Index: libs/libmythtv/videooutwindow.h
===================================================================
--- libs/libmythtv/videooutwindow.h	(revision 19373)
+++ libs/libmythtv/videooutwindow.h	(working copy)
@@ -70,7 +70,6 @@
     float    GetMzScaleV(void)           const { return mz_scale_v;      }
     float    GetMzScaleH(void)           const { return mz_scale_h;      }
     QPoint   GetMzMove(void)             const { return mz_move;         }
-    PIPLocation GetPIPLocation(void)     const { return db_pip_location; }
     int         GetPIPSize(void)         const { return db_pip_size;     }
     PIPState    GetPIPState(void)        const { return pip_state;       }
     QSize  GetVideoDispDim(void)         const { return video_disp_dim;  }
@@ -96,7 +95,8 @@
         { return tmp_display_visible_rect; }
     QRect GetVisibleOSDBounds(float&, float&, float) const;
     QRect GetTotalOSDBounds(void) const;
-    QRect GetPIPRect(int                location,
+
+    QRect GetPIPRect(PIPLocation        location,
                      NuppelVideoPlayer *pipplayer    = NULL,
                      bool               do_pixel_adj = true) const;
 
@@ -112,7 +112,6 @@
     QPoint  db_move;          ///< Percentage move from database
     float   db_scale_horiz;   ///< Horizontal Overscan/Underscan percentage
     float   db_scale_vert;    ///< Vertical Overscan/Underscan percentage
-    PIPLocation db_pip_location;
     int     db_pip_size;      ///< percentage of full window to use for PiP
     bool    db_scaling_allowed;///< disable this to prevent overscan/underscan
 
Index: libs/libmythtv/playercontext.h
===================================================================
--- libs/libmythtv/playercontext.h	(revision 19373)
+++ libs/libmythtv/playercontext.h	(working copy)
@@ -62,20 +62,18 @@
     bool StartPIPPlayer(TV *tv, TVState desiredState);
     void PIPTeardown(void);
     bool isPIP(void) const
-        { return (pipState > kPIPOff && pipState < kPBPLeft); }
+        { return (kPIPonTV == pipState) || (kPIPStandAlone == pipState); }
     bool isPBP(void) const
-        { return (pipState > kPIPStandAlone && pipState < kPBPSwap); }
+        { return (kPBPLeft == pipState) || (kPBPRight      == pipState); }
     bool isMainVideo(void) const
-        { return (pipState == kPIPOff || pipState == kPBPLeft); }
+        { return (kPIPOff  == pipState) || (kPBPLeft       == pipState); }
     void DrawARGBFrame(QPainter *p);
     QRect GetStandAlonePIPRect(void);
-    QString PIPLocationToString(void);
-    QString PIPStateToString(void);
     PIPState GetPIPState(void) const { return pipState; }
     void SetNullVideo(bool setting) { useNullVideo = setting; }
     bool UseNullVideo(void) const { return useNullVideo; }
+    bool IsNVPChangingBuffers(void) const { return nvpUnsafe; }
 
-
     void    PushPreviousChannel(void);
     QString PopPreviousChannel(void);
     QString GetPreviousChannel(void) const;
@@ -90,8 +88,8 @@
     void LockState(void) const;
     void UnlockState(void) const;
     bool InStateChange(void) const;
-    void ChangeState(TVState newState);
-    void ForceNextStateNone(void);
+    void ChangeState(TVState newState, int line);
+    void ForceNextStateNone(int line);
     TVState DequeueNextState(void);
     TVState GetState(void) const;
     /// This is set if the player encountered some irrecoverable error.
@@ -113,11 +111,13 @@
     void SetPlayGroup(const QString &group);
     void SetPseudoLiveTV(const ProgramInfo *pi, PseudoState new_state);
     void SetPIPState(PIPState change) { pipState = change; }
+    void SetNVPChangingBuffers(bool val) { nvpUnsafe = val; }
     void ResizePIPWindow(void);
 
 
   public:
     NuppelVideoPlayer  *nvp;
+    volatile bool       nvpUnsafe;
     RemoteEncoder      *recorder;
     LiveTVChain        *tvchain;
     RingBuffer         *buffer;
Index: libs/libmythtv/videoout_xv.h
===================================================================
--- libs/libmythtv/videoout_xv.h	(revision 19373)
+++ libs/libmythtv/videoout_xv.h	(working copy)
@@ -72,7 +72,8 @@
 
     void ProcessFrame(VideoFrame *frame, OSD *osd,
                       FilterChain *filterList,
-                      NuppelVideoPlayer *pipPlayer);
+                      const PIPMap &pipPlayers);
+
     void PrepareFrame(VideoFrame*, FrameScanType);
     void DrawSlice(VideoFrame*, int x, int y, int w, int h);
     void Show(FrameScanType);
@@ -114,10 +115,11 @@
         { return OpenGL <= VideoOutputSubType(); }
 
     void CheckFrameStates(void);
-    QRect GetPIPRect(int location, 
-                    NuppelVideoPlayer *pipplayer = NULL, 
-                    bool do_pixel_adj = true) const;
 
+    virtual QRect GetPIPRect(PIPLocation        location,
+                             NuppelVideoPlayer *pipplayer = NULL,
+                             bool               do_pixel_adj = true) const;
+
     virtual void ShutdownVideoResize(void);
 
     // OpenGL
@@ -162,14 +164,14 @@
     void DoneDisplayingFrame(void);
 
     void ProcessFrameVDPAU(VideoFrame *frame, OSD *osd,
-                           NuppelVideoPlayer *pipPlayer);
+                           const PIPMap &pipPlayers);
     void ProcessFrameXvMC(VideoFrame *frame, OSD *osd);
     void ProcessFrameOpenGL(VideoFrame *frame, OSD *osd,
                             FilterChain *filterList,
-                            NuppelVideoPlayer *pipPlayer);
+                            const PIPMap &pipPlayers);
     void ProcessFrameMem(VideoFrame *frame, OSD *osd,
                          FilterChain *filterList,
-                         NuppelVideoPlayer *pipPlayer);
+                         const PIPMap &pipPlayers);
 
     void PrepareFrameVDPAU(VideoFrame *, FrameScanType);
     void PrepareFrameXvMC(VideoFrame *, FrameScanType);
@@ -181,7 +183,10 @@
     void ShowXvMC(FrameScanType scan);
     void ShowXVideo(FrameScanType scan);
 
-    void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
+    virtual void ShowPIP(VideoFrame        *frame,
+                         NuppelVideoPlayer *pipplayer,
+                         PIPLocation        loc);
+
     virtual int DisplayOSD(VideoFrame *frame, OSD *osd,
                            int stride = -1, int revision = -1);
 
@@ -307,10 +312,11 @@
     QWaitCondition       gl_context_wait;
     OpenGLContextGLX    *gl_context;
     OpenGLVideo         *gl_videochain;
-    OpenGLVideo         *gl_pipchain;
+    QMap<NuppelVideoPlayer*,OpenGLVideo*> gl_pipchains;
+    QMap<NuppelVideoPlayer*,bool>         gl_pip_ready;
+    OpenGLVideo         *gl_pipchain_active;
     OpenGLVideo         *gl_osdchain;
     bool                 gl_use_osd_opengl2;
-    bool                 gl_pip_ready;
     bool                 gl_osd_ready;
 
     // Chromakey OSD info
Index: libs/libmythtv/videoout_xv.cpp
===================================================================
--- libs/libmythtv/videoout_xv.cpp	(revision 19373)
+++ libs/libmythtv/videoout_xv.cpp	(working copy)
@@ -169,11 +169,10 @@
 
       gl_context_lock(QMutex::Recursive),
       gl_context_creator(NULL), gl_context(NULL),
-      gl_videochain(NULL), gl_pipchain(NULL),
+      gl_videochain(NULL), gl_pipchain_active(NULL),
       gl_osdchain(NULL),
 
       gl_use_osd_opengl2(false),
-      gl_pip_ready(false),
       gl_osd_ready(false),
 
 
@@ -2732,10 +2731,10 @@
         delete gl_videochain;
         gl_videochain = NULL;
     }
-    if (gl_pipchain)
+    while (!gl_pipchains.empty())
     {
-        delete gl_pipchain;
-        gl_pipchain = NULL;
+        delete *gl_pipchains.begin();
+        gl_pipchains.erase(gl_pipchains.begin());
     }
     if (gl_osdchain)
     {
@@ -2750,7 +2749,7 @@
     }
 
     gl_use_osd_opengl2 = false;
-    gl_pip_ready = false;
+    gl_pip_ready.clear();
     gl_osd_ready = false;
 
     // end OpenGL stuff
@@ -3157,9 +3156,15 @@
 
     gl_videochain->PrepareFrame(t, m_deinterlacing, framesPlayed, false);
 
-    if (gl_pip_ready && gl_pipchain)
-        gl_pipchain->PrepareFrame(t, m_deinterlacing, framesPlayed,
-                                  pad_pip_window);
+    QMap<NuppelVideoPlayer*,OpenGLVideo*>::iterator it = gl_pipchains.begin();
+    for (; it != gl_pipchains.end(); ++it)
+    {
+        if (gl_pip_ready[it.key()])
+        {
+            bool active = gl_pipchain_active == *it;
+            (*it)->PrepareFrame(t, m_deinterlacing, framesPlayed, active);
+        }
+    }
 
     if (gl_osd_ready && gl_osdchain)
         gl_osdchain->PrepareFrame(t, m_deinterlacing, framesPlayed, false);
@@ -3577,28 +3582,35 @@
     X11S(XSync(XJ_disp, False));
 }
 
-void VideoOutputXv::ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
+void VideoOutputXv::ShowPIP(VideoFrame        *frame,
+                            NuppelVideoPlayer *pipplayer,
+                            PIPLocation        loc)
 {
+    if (VideoOutputSubType() >= XVideoMC &&
+        VideoOutputSubType() <= XVideoVLD)
+    {
+        return;
+    }
+
     if (VideoOutputSubType() != OpenGL &&
         VideoOutputSubType() != XVideoVDPAU)
     {
-        VideoOutput::ShowPIP(frame, pipplayer);
+        VideoOutput::ShowPIP(frame, pipplayer, loc);
         return;
     }
 
     (void) frame;
 
-    gl_pip_ready = false;
-
     if (!pipplayer)
         return;
 
     int pipw, piph;
-    VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
-    float pipVideoAspect = pipplayer->GetVideoAspect();
-    QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
-    uint  pipVideoWidth  = pipVideoDim.width();
-    uint  pipVideoHeight = pipVideoDim.height();
+    VideoFrame *pipimage       = pipplayer->GetCurrentFrame(pipw, piph);
+    const bool  pipActive      = pipplayer->IsPIPActive();
+    const float pipVideoAspect = pipplayer->GetVideoAspect();
+    const QSize pipVideoDim    = pipplayer->GetVideoBufferSize();
+    const uint  pipVideoWidth  = pipVideoDim.width();
+    const uint  pipVideoHeight = pipVideoDim.height();
 
     // If PiP is not initialized to values we like, silently ignore the frame.
     if ((pipVideoAspect <= 0) || !pipimage || 
@@ -3608,7 +3620,7 @@
         return;
     }
 
-    QRect position = GetPIPRect(windows[0].GetPIPLocation(), pipplayer);
+    QRect position = GetPIPRect(loc, pipplayer);
     QRect dvr = GetTotalVisibleRect();
  
 #ifdef USING_VDPAU
@@ -3620,10 +3632,12 @@
     }
 #endif // USING_VDPAU
 
+    gl_pip_ready[pipplayer] = false;
+    OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
     if (!gl_pipchain)
     {
         VERBOSE(VB_PLAYBACK, LOC + "Initialise PiP.");
-        gl_pipchain = new OpenGLVideo();
+        gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
         bool success = gl_pipchain->Init(gl_context, db_use_picture_controls,
                      QSize(pipVideoWidth, pipVideoHeight),
                      dvr, position,
@@ -3643,7 +3657,7 @@
     {
         VERBOSE(VB_PLAYBACK, LOC + "Re-initialise PiP.");
         delete gl_pipchain;
-        gl_pipchain = new OpenGLVideo();
+        gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
         bool success = gl_pipchain->Init(
             gl_context, db_use_picture_controls,
             QSize(pipVideoWidth, pipVideoHeight),
@@ -3663,8 +3677,11 @@
                               QRect(0, 0, pipVideoWidth, pipVideoHeight));
     gl_pipchain->UpdateInputFrame(pipimage);
 
-    gl_pip_ready = true;
+    gl_pip_ready[pipplayer] = true;
 
+    if (pipActive)
+        gl_pipchain_active = gl_pipchain;
+
     pipplayer->ReleaseCurrentFrame(pipimage);
 }
 
@@ -4058,7 +4075,7 @@
 }
 
 void VideoOutputXv::ProcessFrameVDPAU(VideoFrame *frame, OSD *osd,
-                                      NuppelVideoPlayer *pipPlayer)
+                                      const PIPMap &pipPlayers)
 {
     if (!frame)
     {
@@ -4069,7 +4086,7 @@
 
     if (vdpau_use_osd && osd)
         DisplayOSD(frame, osd);
-    ShowPIP(frame, pipPlayer);
+    ShowPIPs(frame, pipPlayers);
 }
 
 void VideoOutputXv::ProcessFrameXvMC(VideoFrame *frame, OSD *osd)
@@ -4278,11 +4295,11 @@
 
 void VideoOutputXv::ProcessFrameOpenGL(VideoFrame *frame, OSD *osd,
                                        FilterChain *filterList,
-                                       NuppelVideoPlayer *pipPlayer)
+                                       const PIPMap &pipPlayers)
 {
     (void) osd;
     (void) filterList;
-    (void) pipPlayer;
+    (void) pipPlayers;
 
     if (!gl_videochain || !gl_context)
         return;
@@ -4309,7 +4326,8 @@
     
     if (!windows[0].IsEmbedding())
     {
-        ShowPIP(frame, pipPlayer);
+        gl_pipchain_active = NULL;
+        ShowPIPs(frame, pipPlayers);
         if (osd)
             DisplayOSD(frame, osd);
     }
@@ -4322,7 +4340,7 @@
 
 void VideoOutputXv::ProcessFrameMem(VideoFrame *frame, OSD *osd,
                                     FilterChain *filterList,
-                                    NuppelVideoPlayer *pipPlayer)
+                                    const PIPMap &pipPlayers)
 {
     bool deint_proc = m_deinterlacing && (m_deintFilter != NULL);
     bool pauseframe = false;
@@ -4350,7 +4368,7 @@
             m_deintFilter->ProcessFrame(frame);
     }
 
-    ShowPIP(frame, pipPlayer);
+    ShowPIPs(frame, pipPlayers);
 
     if (osd && !windows[0].IsEmbedding())
     {
@@ -4376,7 +4394,7 @@
 // this is documented in videooutbase.cpp
 void VideoOutputXv::ProcessFrame(VideoFrame *frame, OSD *osd,
                                  FilterChain *filterList,
-                                 NuppelVideoPlayer *pipPlayer)
+                                 const PIPMap &pipPlayers)
 {
     if (IsErrored())
     {
@@ -4385,11 +4403,11 @@
     }
 
     if (VideoOutputSubType() == XVideoVDPAU)
-        ProcessFrameVDPAU(frame, osd, pipPlayer);
+        ProcessFrameVDPAU(frame, osd, pipPlayers);
     else if (VideoOutputSubType() == OpenGL)
-        ProcessFrameOpenGL(frame, osd, filterList, pipPlayer);
+        ProcessFrameOpenGL(frame, osd, filterList, pipPlayers);
     else if (VideoOutputSubType() <= XVideo)
-        ProcessFrameMem(frame, osd, filterList, pipPlayer);
+        ProcessFrameMem(frame, osd, filterList, pipPlayers);
     else
         ProcessFrameXvMC(frame, osd);
 }
@@ -4747,8 +4765,9 @@
 #endif // USING_XVMC
 }
 
-QRect VideoOutputXv::GetPIPRect(int location, NuppelVideoPlayer *pipplayer,
-                                bool do_pixel_adj) const
+QRect VideoOutputXv::GetPIPRect(PIPLocation        location,
+                                NuppelVideoPlayer *pipplayer,
+                                bool               do_pixel_adj) const
 {
     (void)do_pixel_adj;
 
Index: libs/libmythtv/videooutbase.h
===================================================================
--- libs/libmythtv/videooutbase.h	(revision 19373)
+++ libs/libmythtv/videooutbase.h	(working copy)
@@ -30,6 +30,8 @@
 class VideoDisplayProfile;
 class OpenGLContextGLX;
 
+typedef QMap<NuppelVideoPlayer*,PIPLocation> PIPMap;
+
 extern "C" {
 struct ImgReSampleContext;
 }
@@ -115,7 +117,7 @@
     // pass in null to use the pause frame, if it exists.
     virtual void ProcessFrame(VideoFrame *frame, OSD *osd,
                               FilterChain *filterList,
-                              NuppelVideoPlayer *pipPlayer) = 0;
+                              const PIPMap &pipPlayers) = 0;
 
     /// \brief Tells video output that a full repaint is needed.
     void ExposeEvent(void);
@@ -228,12 +230,11 @@
     bool IsVideoScalingAllowed(void) const;
 
     /// \brief returns QRect of PIP based on PIPLocation
-    virtual QRect GetPIPRect(int location,
+    virtual QRect GetPIPRect(PIPLocation location,
                              NuppelVideoPlayer *pipplayer = NULL,
                              bool do_pixel_adj = true) const;
 
     virtual void SetPIPState(PIPState setting);
-    virtual void PadPIPImage(bool change) { pad_pip_window = change; }
 
     virtual QString GetOSDRenderer(void) const;
 
@@ -245,7 +246,11 @@
                      int needprebuffer_normal, int needprebuffer_small,
                      int keepprebuffer);
 
-    virtual void ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer);
+    virtual void ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers);
+    virtual void ShowPIP(VideoFrame        *frame,
+                         NuppelVideoPlayer *pipplayer,
+                         PIPLocation        loc);
+
     virtual int DisplayOSD(VideoFrame *frame, OSD *osd, int stride = -1, int revision = -1);
 
     virtual void SetPictureAttributeDBValue(
@@ -288,7 +293,6 @@
     unsigned char      *pip_tmp_buf;
     unsigned char      *pip_tmp_buf2;
     ImgReSampleContext *pip_scaling_context;
-    bool pad_pip_window;
     VideoFrame pip_tmp_image;
 
     // Video resizing (for ITV)
Index: libs/libmythtv/videoout_ivtv.cpp
===================================================================
--- libs/libmythtv/videoout_ivtv.cpp	(revision 19373)
+++ libs/libmythtv/videoout_ivtv.cpp	(working copy)
@@ -693,7 +693,9 @@
 { 
 }
 
-void VideoOutputIvtv::ShowPIP(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
+void VideoOutputIvtv::ShowPIP(VideoFrame        *frame,
+                              NuppelVideoPlayer *pipplayer,
+                              PIPLocation        loc)
 {
     if (!pipplayer)
         return;
@@ -738,7 +740,7 @@
         }
     }
 
-    switch (windows[0].GetPIPLocation())
+    switch (loc)
     {
         case kPIP_END:
         case kPIPTopLeft:
@@ -782,7 +784,7 @@
 
 void VideoOutputIvtv::ProcessFrame(VideoFrame *frame, OSD *osd,
                                    FilterChain *filterList, 
-                                   NuppelVideoPlayer *pipPlayer) 
+                                   const PIPMap &pipPlayers)
 { 
     (void)filterList;
     (void)frame;
@@ -813,7 +815,7 @@
         surface = osd->Display();
 
     // Clear osdbuf if OSD has changed, or PiP has been toggled
-    bool clear = (pipPlayer!=0) ^ pipon;
+    bool clear = (!pipPlayers.empty()) ^ pipon;
     int new_revision = osdbuf_revision;
     if (surface)
     {
@@ -828,9 +830,9 @@
         drawanyway = true;
     }
 
-    if (pipPlayer)
+    if (!pipPlayers.empty())
     {
-        ShowPIP(&tmpframe, pipPlayer);
+        ShowPIPs(&tmpframe, pipPlayers);
         osdbuf_revision = 0xfffffff; // make sure OSD is redrawn
         lastcleared = false;
         drawanyway  = true;
@@ -849,8 +851,8 @@
         {
             bzero(tmpframe.buf, video_dim.height() * stride);
             // redraw PiP...
-            if (pipPlayer)
-                ShowPIP(&tmpframe, pipPlayer);
+            if (!pipPlayers.empty())
+                ShowPIPs(&tmpframe, pipPlayers);
         }
         drawanyway  |= !lastcleared || pipon;
         lastcleared &= !pipon;
@@ -858,7 +860,7 @@
 
     // Set these so we know if/how to clear if need be, the next time around.
     osdon = (ret >= 0);
-    pipon = (bool) pipPlayer;
+    pipon = (bool) !pipPlayers.empty();
 
     // If there is an OSD, make sure we draw OSD surface
     lastcleared &= !osdon;
Index: libs/libmythtv/videoout_null.h
===================================================================
--- libs/libmythtv/videoout_null.h	(revision 19373)
+++ libs/libmythtv/videoout_null.h	(working copy)
@@ -37,7 +37,7 @@
     void UpdatePauseFrame(void);
     void ProcessFrame(VideoFrame *frame, OSD *osd,
                       FilterChain *filterList,
-                      NuppelVideoPlayer *pipPlayer);
+                      const PIPMap &pipPlayers);
 
     static QStringList GetAllowedRenderers(MythCodecID myth_codec_id,
                                            const QSize &video_dim);
