Index: libs/libmythtv/mythbdplayer.h
===================================================================
--- libs/libmythtv/mythbdplayer.h	(revision 25722)
+++ libs/libmythtv/mythbdplayer.h	(working copy)
@@ -13,12 +13,18 @@
     virtual int64_t GetChapter(int chapter);
 
     virtual int GetNumTitles(void) const;
+    virtual int GetNumAngles(void) const;
     virtual int GetCurrentTitle(void) const;
+    virtual int GetCurrentAngle(void) const;
     virtual int GetTitleDuration(int title) const;
     virtual QString GetTitleName(int title) const;
+    virtual QString GetAngleName(int angle) const;
     virtual bool SwitchTitle(int title);
     virtual bool PrevTitle(void);
     virtual bool NextTitle(void);
+    virtual bool SwitchAngle(int angle);
+    virtual bool PrevAngle(void);
+    virtual bool NextAngle(void);
 };
 
 #endif // MYTHBDPLAYER_H
Index: libs/libmythtv/DVDRingBuffer.cpp
===================================================================
--- libs/libmythtv/DVDRingBuffer.cpp	(revision 25722)
+++ libs/libmythtv/DVDRingBuffer.cpp	(working copy)
@@ -38,7 +38,8 @@
       m_currentpos(0),
       m_lastNav(NULL),    m_part(0),
       m_title(0),         m_titleParts(0),
-      m_gotStop(false),
+      m_gotStop(false),   m_currentAngle(0),
+      m_currentTitleAngleCount(0),
       m_cellHasStillFrame(false), m_audioStreamsChanged(false),
       m_dvdWaiting(false),
       m_titleLength(0), m_hl_button(0, 0, 0, 0),
@@ -187,6 +188,7 @@
 
         int32_t numTitles  = 0;
         m_titleParts = 0;
+
         dvdnav_title_play(m_dvdnav, 0);
         dvdRet = dvdnav_get_number_of_titles(m_dvdnav, &numTitles);
         if (numTitles == 0 )
@@ -220,6 +222,7 @@
         dvdnav_current_title_info(m_dvdnav, &m_title, &m_part);
         dvdnav_get_title_string(m_dvdnav, &m_dvdname);
         dvdnav_get_serial_string(m_dvdnav, &m_serialnumber);
+        dvdnav_get_angle_info(m_dvdnav, &m_currentAngle, &m_currentTitleAngleCount);
         SetDVDSpeed();
         VERBOSE(VB_PLAYBACK, QString("DVD Serial Number %1").arg(m_serialnumber));
         return true;
@@ -1498,3 +1501,24 @@
     s->rects[0]->y += y1;
     return 1;
 }
+
+bool DVDRingBufferPriv::SwitchAngle(uint angle)
+{
+    if (m_dvdnav)
+    {
+        VERBOSE(VB_IMPORTANT, LOC + QString("Switching to Angle %1...")
+                .arg(angle));
+        dvdnav_status_t status = dvdnav_angle_change(m_dvdnav,
+                                                    (int32_t)angle);
+        if (status == DVDNAV_STATUS_OK)
+        {
+            m_currentAngle = angle;
+            return true;
+        }
+        else
+            return false;
+    }
+    else
+        return false;
+}
+
Index: libs/libmythtv/tv_play.h
===================================================================
--- libs/libmythtv/tv_play.h	(revision 25722)
+++ libs/libmythtv/tv_play.h	(working copy)
@@ -448,6 +448,10 @@
     int  GetTitleDuration(const PlayerContext *ctx, int title) const;
     QString GetTitleName(const PlayerContext *ctx, int title) const;
     void DoSwitchTitle(PlayerContext*, int title);
+    int  GetNumAngles(const PlayerContext *ctx) const;
+    int  GetCurrentAngle(const PlayerContext *ctx) const;
+    QString GetAngleName(const PlayerContext *ctx, int angle) const;
+    void DoSwitchAngle(PlayerContext*, int angle);
     void DoJumpChapter(PlayerContext*, int direction);
     void DoSkipCommercials(PlayerContext*, int direction);
 
Index: libs/libmythtv/BDRingBuffer.cpp
===================================================================
--- libs/libmythtv/BDRingBuffer.cpp	(revision 25722)
+++ libs/libmythtv/BDRingBuffer.cpp	(working copy)
@@ -72,6 +72,8 @@
         m_titlesize = 0;
         m_currentTime = 0;
         m_currentTitleInfo = NULL;
+        m_currentTitleAngleCount = 0;
+        m_currentAngle = 0;
 
         VERBOSE(VB_IMPORTANT, LOC + QString("Found %1 relevant titles.")
                 .arg(m_numTitles));
@@ -164,15 +166,18 @@
             return false;
 
         m_currentTitleLength = m_currentTitleInfo->duration;
+        m_currentTitleAngleCount = m_currentTitleInfo->angle_count;
+        m_currentAngle = 0;
         bd_select_title(bdnav, title);
         uint32_t chapter_count = m_currentTitleInfo->chapter_count;
         VERBOSE(VB_IMPORTANT, LOC + QString("Selected title: index %1. "
                                             "Duration: %2 (%3 mins) "
-                                            "Number of Chapters: %4")
+                                            "Number of Chapters: %4 Number of Angles: %5")
                                             .arg(title)
                                             .arg(m_currentTitleLength)
                                             .arg(m_currentTitleLength / (90000 * 60))
-                                            .arg(chapter_count));
+                                            .arg(chapter_count)
+                                            .arg(m_currentTitleAngleCount));
         VERBOSE(VB_PLAYBACK, LOC + QString("Frame Rate: %1").arg(GetFrameRate()));
         if (chapter_count)
         {
@@ -198,6 +203,20 @@
         return false;
 }
 
+bool BDRingBufferPriv::SwitchAngle(uint angle)
+{
+    if (bdnav)
+    {
+        VERBOSE(VB_IMPORTANT, LOC + QString("Switching to Angle %1...")
+                .arg(angle));
+        bd_seamless_angle_change(bdnav, angle);
+        m_currentAngle = angle;
+        return true;
+    }
+    else
+        return false;
+}
+
 uint64_t BDRingBufferPriv::GetTotalReadPosition(void)
 {
     if (bdnav)
@@ -289,4 +308,4 @@
     }
 
     return iso639_str3_to_key("und");
-}
\ No newline at end of file
+}
Index: libs/libmythtv/mythdvdplayer.h
===================================================================
--- libs/libmythtv/mythdvdplayer.h	(revision 25722)
+++ libs/libmythtv/mythdvdplayer.h	(working copy)
@@ -46,6 +46,11 @@
 
     void HideDVDButton(bool hide) { hidedvdbutton = hide; }
 
+    virtual int GetNumAngles(void) const;
+    virtual int GetCurrentAngle(void) const;
+    virtual QString GetAngleName(int angle) const;
+    virtual bool SwitchAngle(int angle);
+
   private:
     void SetDVDBookmark(uint64_t frame);
     void DisplayDVDButton(void);
Index: libs/libmythtv/mythbdplayer.cpp
===================================================================
--- libs/libmythtv/mythbdplayer.cpp	(revision 25722)
+++ libs/libmythtv/mythbdplayer.cpp	(working copy)
@@ -61,6 +61,13 @@
     return 0;
 }
 
+int MythBDPlayer::GetNumAngles(void) const
+{
+    if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
+        return player_ctx->buffer->BD()->GetNumAngles();
+    return 0;
+}
+
 int MythBDPlayer::GetCurrentTitle(void) const
 {
     if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
@@ -68,6 +75,13 @@
     return -1;
 }
 
+int MythBDPlayer::GetCurrentAngle(void) const
+{
+    if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
+        return player_ctx->buffer->BD()->GetCurrentAngle();
+    return -1; 
+}
+
 int MythBDPlayer::GetTitleDuration(int title) const
 {
     if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen() &&
@@ -95,6 +109,16 @@
     return QString();
 }
 
+QString MythBDPlayer::GetAngleName(int angle) const
+{
+    if (angle >= 0 && angle < GetNumAngles())
+    {
+        QString name = QObject::tr("Angle %1").arg(angle+1);
+        return name;
+    }
+    return QString();
+}
+
 bool MythBDPlayer::SwitchTitle(int title)
 {
     uint total = GetNumTitles();
@@ -134,3 +158,44 @@
 
     return SwitchTitle(prev);
 }
+
+bool MythBDPlayer::SwitchAngle(int angle)
+{
+    uint total = GetNumAngles();
+    if (!total || angle == GetCurrentAngle())
+        return false;
+
+    if (angle >= (int)total)
+        angle = 0;
+
+    bool ok = static_cast<bool>(player_ctx->buffer->BD()->SwitchAngle(angle));
+
+    return ok;
+}
+
+bool MythBDPlayer::NextAngle(void)
+{
+    uint total = GetNumAngles();
+    int next = GetCurrentAngle() + 1;
+    if (!total)
+        return false;
+
+    if (next >= (int)total)
+        next = 0;
+
+    return SwitchAngle(next);
+}
+
+bool MythBDPlayer::PrevAngle(void)
+{
+    uint total = GetNumAngles();
+    int prev = GetCurrentAngle() - 1;
+    if (!total || total == 1)
+        return false;
+
+    if (prev < 0)
+        prev = total;
+
+    return SwitchAngle(prev);
+}
+
Index: libs/libmythtv/mythplayer.h
===================================================================
--- libs/libmythtv/mythplayer.h	(revision 25722)
+++ libs/libmythtv/mythplayer.h	(working copy)
@@ -269,6 +269,11 @@
     virtual bool NextTitle(void) { return false; }
     virtual bool PrevTitle(void) { return false; }
 
+    // Angle stuff
+    virtual bool SwitchAngle(int title) { return false; }
+    virtual bool NextAngle(void) { return false; }
+    virtual bool PrevAngle(void) { return false; }
+
     // Commercial stuff
     void SetAutoCommercialSkip(CommSkipMode autoskip)
         { commBreakMap.SetAutoCommercialSkip(autoskip, framesPlayed); }
@@ -389,6 +394,11 @@
     virtual int GetTitleDuration(int title) const { return 0; }
     virtual QString GetTitleName(int title) const { return QString(); }
 
+    // Angle public stuff
+    virtual int GetNumAngles(void) const { return 0; }
+    virtual int GetCurrentAngle(void) const { return 0; }
+    virtual QString GetAngleName(int title) const { return QString(); }
+
     // DVD public stuff
     virtual void ChangeDVDTrack(bool ffw)       { (void) ffw;       }
     virtual bool GoToDVDMenu(QString str)       { return false;     }
Index: libs/libmythtv/mythdvdplayer.cpp
===================================================================
--- libs/libmythtv/mythdvdplayer.cpp	(revision 25722)
+++ libs/libmythtv/mythdvdplayer.cpp	(working copy)
@@ -465,3 +465,42 @@
     }
     player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
 }
+
+int MythDVDPlayer::GetNumAngles(void) const
+{
+    if (player_ctx->buffer->DVD() && player_ctx->buffer->DVD()->IsOpen())
+        return player_ctx->buffer->DVD()->GetNumAngles();
+    return 0;
+}
+
+int MythDVDPlayer::GetCurrentAngle(void) const
+{
+    if (player_ctx->buffer->DVD() && player_ctx->buffer->DVD()->IsOpen())
+        return player_ctx->buffer->DVD()->GetCurrentAngle();
+    return -1; 
+}
+
+QString MythDVDPlayer::GetAngleName(int angle) const
+{
+    if (angle >= 0 && angle < GetNumAngles())
+    {
+        QString name = QObject::tr("Angle %1").arg(angle+1);
+        return name;
+    }
+    return QString();
+}
+
+bool MythDVDPlayer::SwitchAngle(int angle)
+{
+    uint total = GetNumAngles();
+    if (!total || angle == GetCurrentAngle())
+        return false;
+
+    if (angle >= (int)total)
+        angle = 0;
+
+    bool ok = static_cast<bool>(player_ctx->buffer->DVD()->SwitchAngle(angle));
+
+    return ok;
+}
+
Index: libs/libmythtv/DVDRingBuffer.h
===================================================================
--- libs/libmythtv/DVDRingBuffer.h	(revision 25722)
+++ libs/libmythtv/DVDRingBuffer.h	(working copy)
@@ -34,6 +34,8 @@
     // gets
     int  GetTitle(void) const { return m_title;        }
     int  GetPart(void)  const { return m_part;         }
+    int GetCurrentAngle(void) const { return m_currentAngle; };
+    int GetNumAngles(void) { return m_currentTitleAngleCount; };
     bool IsInMenu(bool update = false);
     bool IsOpen(void)   const { return m_dvdnav;       }
     long long GetReadPosition(void);
@@ -108,6 +110,7 @@
     void JumpToTitle(bool change) { m_jumptotitle = change; }
     void SetDVDSpeed(void);
     void SetDVDSpeed(int speed);
+    bool SwitchAngle(uint angle);
 
     void SetParent(MythDVDPlayer *p) { m_parent = p; }
 
@@ -130,6 +133,8 @@
     int32_t        m_title;
     int32_t        m_titleParts;
     bool           m_gotStop;
+    int            m_currentAngle;
+    int            m_currentTitleAngleCount;
 
     bool           m_cellHasStillFrame;
     bool           m_audioStreamsChanged;
Index: libs/libmythtv/tv_play.cpp
===================================================================
--- libs/libmythtv/tv_play.cpp	(revision 25722)
+++ libs/libmythtv/tv_play.cpp	(working copy)
@@ -6044,6 +6044,36 @@
     return currentTitle;
 }
 
+int TV::GetNumAngles(const PlayerContext *ctx) const
+{
+    int num_angles = 0;
+    ctx->LockDeletePlayer(__FILE__, __LINE__);
+    if (ctx->player)
+        num_angles = ctx->player->GetNumAngles();
+    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
+    return num_angles;
+}
+
+int TV::GetCurrentAngle(const PlayerContext *ctx) const
+{
+    int currentAngle = 0;
+    ctx->LockDeletePlayer(__FILE__, __LINE__);
+    if (ctx->player)
+        currentAngle = ctx->player->GetCurrentAngle();
+    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
+    return currentAngle;
+}
+
+QString TV::GetAngleName(const PlayerContext *ctx, int angle) const
+{
+    QString name;
+    ctx->LockDeletePlayer(__FILE__, __LINE__);
+    if (ctx->player)
+        name = ctx->player->GetAngleName(angle);
+    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
+    return name;
+}
+
 int TV::GetTitleDuration(const PlayerContext *ctx, int title) const
 {
     int seconds = 0;
@@ -6086,6 +6116,27 @@
     ctx->UnlockDeletePlayer(__FILE__, __LINE__);
 }
 
+void TV::DoSwitchAngle(PlayerContext *ctx, int angle)
+{
+    NormalSpeed(ctx);
+    StopFFRew(ctx);
+
+    PauseAudioUntilBuffered(ctx);
+
+    osdInfo info;
+    ctx->CalcPlayerSliderPosition(info);
+    info.text["description"] = tr("Switch Angle");
+    info.text["title"] = tr("Switching");
+    UpdateOSDStatus(ctx, info, kOSDFunctionalType_Default, kOSDTimeout_Med);
+
+    ctx->LockDeletePlayer(__FILE__, __LINE__);
+    if (ctx->player)
+    {
+        ctx->player->SwitchAngle(angle);
+    }
+    ctx->UnlockDeletePlayer(__FILE__, __LINE__);
+}
+
 void TV::DoSkipCommercials(PlayerContext *ctx, int direction)
 {
     NormalSpeed(ctx);
@@ -9989,6 +10040,11 @@
             int title = action.right(3).toInt();
             DoSwitchTitle(actx, title);
         }
+        else if (action.left(13) == "SWITCHTOANGLE")
+        {
+            int angle = action.right(3).toInt();
+            DoSwitchAngle(actx, angle);
+        }
         else if (action == "EDIT")
             StartProgramEditMode(actx);
         else if (action == "TOGGLEAUTOEXPIRE")
@@ -10409,6 +10465,7 @@
 {
     int num_chapters  = GetNumChapters(ctx);
     int num_titles    = GetNumTitles(ctx);
+    int num_angles    = GetNumAngles(ctx);
     TVState state     = ctx->GetState();
     bool isdvd        = state == kState_WatchingDVD;
     bool islivetv     = StateIsLiveTV(state);
@@ -10459,6 +10516,11 @@
             osd->DialogAddButton(tr("Chapter"), "DIALOG_MENU_AVCHAPTER_0",
                                  true, selected == "AVCHAPTER");
         }
+        if (num_angles > 1)
+        {
+            osd->DialogAddButton(tr("Angle"), "DIALOG_MENU_AVANGLE_0",
+                                 true, selected == "AVANGLE");
+        }
         if (num_titles)
         {
             osd->DialogAddButton(tr("Title"), "DIALOG_MENU_AVTITLE_0",
@@ -10507,6 +10569,20 @@
                                  false, current_title == i);
         }
     }
+    else if (category == "AVANGLE")
+    {
+        backaction = "NAVIGATE";
+        currenttext = tr("Angle");
+        int current_angle = GetCurrentAngle(ctx);
+
+        for (int i = 0; i < num_angles; i++)
+        {
+            QString angleIdx = QString("%1").arg(i, 3, 10, QChar(48));
+            QString desc = GetAngleName(ctx, i);
+            osd->DialogAddButton(desc, QString("SWITCHTOANGLE%1").arg(angleIdx),
+                                 false, current_angle == i);
+        }
+    }
     else if (category == "COMMSKIP")
     {
         backaction = "NAVIGATE";
Index: libs/libmythtv/BDRingBuffer.h
===================================================================
--- libs/libmythtv/BDRingBuffer.h	(revision 25722)
+++ libs/libmythtv/BDRingBuffer.h	(working copy)
@@ -25,6 +25,7 @@
 
     uint32_t GetNumTitles(void) const { return m_numTitles; }
     int      GetCurrentTitle(void) const;
+    uint64_t GetCurrentAngle(void) const { return m_currentAngle; };
     int      GetTitleDuration(int title) const;
     // Get the size in bytes of the current title (playlist item).
     uint64_t GetTitleSize(void) const { return m_titlesize; }
@@ -34,6 +35,7 @@
     uint64_t GetReadPosition(void);
     uint64_t GetTotalReadPosition(void);
     uint32_t GetNumChapters(void);
+    uint64_t GetNumAngles(void) { return m_currentTitleAngleCount; };
     uint64_t GetChapterStartTime(uint32_t chapter);
     uint64_t GetChapterStartFrame(uint32_t chapter);
     bool IsOpen(void)        const { return bdnav; }
@@ -49,6 +51,7 @@
     void close(void);
 
     bool SwitchTitle(uint title);
+    bool SwitchAngle(uint angle);
 
     int  safe_read(void *data, unsigned sz);
     uint64_t Seek(uint64_t pos);
@@ -60,6 +63,8 @@
     uint64_t           m_currentTitleLength; // Selected title's duration, in ticks (90Khz)
     BLURAY_TITLE_INFO *m_currentTitleInfo; // Selected title info from struct in bluray.h
     uint64_t           m_titlesize;
+    uint64_t           m_currentAngle;
+    uint64_t           m_currentTitleAngleCount;
     uint64_t           m_currentTime;
 };
 #endif
