Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 23097)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -169,6 +169,8 @@
       transcoding(false),
       hasFullPositionMap(false),    limitKeyRepeat(false),
       errorMsg(QString::null),      errorType(kError_None),
+      // Chapter stuff
+      jumpchapter(0),
       // Bookmark stuff
       bookmarkseek(0),              previewFromBookmark(false),
       // Seek
@@ -3248,6 +3250,12 @@
 }
 
 
+void NuppelVideoPlayer::JumpChapter(int direction)
+{
+    if (jumpchapter == 0)
+        jumpchapter = direction;
+}
+
 void NuppelVideoPlayer::SkipCommercials(int direction)
 {
     if (skipcommercials == 0)
@@ -3576,6 +3584,7 @@
     }
 
     rewindtime = fftime = 0;
+    jumpchapter = 0;
     skipcommercials = 0;
 
     if (bookmarkseek > 30)
@@ -3782,6 +3791,12 @@
                 RefreshPauseFrame();
                 need_change_dvd_track = 0;
             }
+            else if (jumpchapter != 0)
+            {
+                DoJumpChapter(jumpchapter);
+                RefreshPauseFrame();
+                jumpchapter = 0;
+            }
             else if (player_ctx->tvchain && player_ctx->tvchain->NeedsToJump())
             {
                 JumpToProgram();
@@ -3844,6 +3859,17 @@
             need_change_dvd_track = 0;
         }
 
+        if (jumpchapter != 0)
+        {
+            QMutexLocker locker(&internalPauseLock);
+
+            PauseVideo(true);
+            DoJumpChapter(jumpchapter);
+            UnpauseVideo(true);
+
+            jumpchapter = 0;
+        }
+
         if (skipcommercials != 0 && ffrew_skip == 1)
         {
             QMutexLocker locker(&internalPauseLock);
@@ -6660,6 +6686,40 @@
     }
 }
 
+int NuppelVideoPlayer::GetNumChapters()
+{
+    return GetDecoder()->GetNumChapters();
+}
+
+bool NuppelVideoPlayer::DoJumpChapter(int direction)
+{
+  int desiredFrame;
+
+  if (direction == -1)
+  {
+      desiredFrame = GetDecoder()->GetPrevChapter(framesPlayed);
+  }
+  else
+  {
+      desiredFrame = GetDecoder()->GetNextChapter(framesPlayed);
+  }
+
+  if (paused && !editmode)
+      GetDecoder()->setExactSeeks(true);
+  if (direction == -1)
+      GetDecoder()->DoRewind(desiredFrame);
+  else
+      GetDecoder()->DoFastForward(desiredFrame);
+  GetDecoder()->setExactSeeks(exactseeks);
+
+  // Note: The video output will be reset by what the the decoder
+  //       does, so we only need to reset the audio, subtitles, etc.
+  ClearAfterSeek(false);
+
+  lastSkipTime = time(NULL);
+  return true;
+}
+
 bool NuppelVideoPlayer::DoSkipCommercials(int direction)
 {
     if (!hascommbreaktable)
Index: libs/libmythtv/decoderbase.h
===================================================================
--- libs/libmythtv/decoderbase.h	(revision 23097)
+++ libs/libmythtv/decoderbase.h	(working copy)
@@ -78,6 +78,9 @@
     virtual bool GetFrame(int onlyvideo) = 0;
     NuppelVideoPlayer *GetNVP() { return m_parent; }
 
+    virtual int GetNumChapters(void) { return 0; }
+    virtual int GetNextChapter(int framesPlayed) { return framesPlayed; }
+    virtual int GetPrevChapter(int framesPlayed) { return framesPlayed; }
     virtual bool DoRewind(long long desiredFrame, bool doflush = true);
     virtual bool DoFastForward(long long desiredFrame, bool doflush = true);
 
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 23097)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -561,6 +561,59 @@
     return  ((lsb - base_ts)&mask);
 }
 
+int AvFormatDecoder::GetNumChapters()
+{
+  return ic->nb_chapters;
+}
+
+int AvFormatDecoder::GetPrevChapter(int framesPlayed)
+{
+    int framenum;
+    int prevframenum = framesPlayed;
+    int prevchapter = 0;
+    for (int i=0; i < ic->nb_chapters; i++)
+    {
+        int num = ic->chapters[i]->time_base.num;
+        int den = ic->chapters[i]->time_base.den;
+        int64_t start = ic->chapters[i]->start;
+        int64_t end = ic->chapters[i]->end;
+        double total_secs = (double)((long double)start * (long double)num / (long double)den);
+        framenum = (int)(total_secs * fps);
+        if (framenum > (framesPlayed - (int)fps))
+        {
+            VERBOSE(VB_PLAYBACK, LOC +
+                    QString("GetPrevChapter(selected chapter %1 framenum %2)")
+                            .arg(prevchapter).arg(prevframenum));
+            return prevframenum;
+        }
+        prevframenum = framenum;
+        prevchapter = i;
+    }
+    return framenum;
+}
+
+int AvFormatDecoder::GetNextChapter(int framesPlayed)
+{
+    int framenum;
+    for (int i=0; i < ic->nb_chapters; i++)
+    {
+        int num = ic->chapters[i]->time_base.num;
+        int den = ic->chapters[i]->time_base.den;
+        int64_t start = ic->chapters[i]->start;
+        int64_t end = ic->chapters[i]->end;
+        double total_secs = (double)((long double)start * (long double)num / (long double)den);
+        framenum = (int)(total_secs * fps);
+        if (framenum > framesPlayed)
+        {
+            VERBOSE(VB_IMPORTANT, LOC +
+                    QString("GetNextChapter(selected chapter %1 framenum %2)")
+                            .arg(i).arg(framenum));
+            return framenum;
+        }
+    }
+    return framesPlayed;
+}
+
 bool AvFormatDecoder::DoRewind(long long desiredFrame, bool discardFrames)
 {
     VERBOSE(VB_PLAYBACK, LOC + "DoRewind("
@@ -1080,6 +1133,25 @@
             QString("Successfully opened decoder for file: "
                     "\"%1\". novideo(%2)").arg(filename).arg(novideo));
 
+    // Print AVContext chapter information
+    for (int i=0; i < ic->nb_chapters; i++)
+    {
+        int id = ic->chapters[i]->id;
+        int num = ic->chapters[i]->time_base.num;
+        int den = ic->chapters[i]->time_base.den;
+        int64_t start = ic->chapters[i]->start;
+        int64_t end = ic->chapters[i]->end;
+        double total_secs = (double)((long double)start * (long double)num / (long double)den);
+        int hours = (int)total_secs / 60 / 60;
+        int minutes = ((int)total_secs / 60) - (hours * 60);
+        double secs = total_secs - (double)((hours * 60 * 60) - (minutes * 60));
+        VERBOSE(VB_PLAYBACK, LOC + QString("Chapter %1 found %2:%3:%4")
+                .arg(QString().sprintf("%02d", i))
+                .arg(QString().sprintf("%02d", hours))
+                .arg(QString().sprintf("%02d", minutes))
+                .arg(QString().sprintf("%02.3f", secs)));
+    }
+
     // Return true if recording has position map
     return recordingHasPositionMap;
 }
Index: libs/libmythtv/tv_play.h
===================================================================
--- libs/libmythtv/tv_play.h	(revision 23097)
+++ libs/libmythtv/tv_play.h	(working copy)
@@ -436,6 +436,8 @@
     float StopFFRew(PlayerContext*);
     void ChangeFFRew(PlayerContext*, int direction);
     void SetFFRew(PlayerContext*, int index);
+    int GetNumChapters(PlayerContext*);
+    void DoJumpChapter(PlayerContext*, int direction);
     void DoSkipCommercials(PlayerContext*, int direction);
     void StartProgramEditMode(PlayerContext*);
 
Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 23097)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -265,6 +265,9 @@
     bool RebuildSeekTable(bool showPercentage = true, StatusCallback cb = NULL,
                           void* cbData = NULL);
 
+    // Chapter stuff
+    void JumpChapter(int direction);
+
     // Commercial stuff
     void SkipCommercials(int direction);
     int FlagCommercials(bool showPercentage, bool fullSpeed,
@@ -409,6 +412,9 @@
     void CheckTVChain();
     void FileChangedCallback();
 
+    // Chapter public stuff
+    int GetNumChapters();
+
     // DVD public stuff
     void ChangeDVDTrack(bool ffw);
     void ActivateDVDButton(void);
@@ -486,6 +492,9 @@
     void JumpToNetFrame(long long net) { JumpToFrame(framesPlayed + net); }
     void RefreshPauseFrame(void);
 
+    // Private chapter stuff
+    bool DoJumpChapter(int direction);
+
     // Private commercial skipping
     void SkipCommercialsByBlanks(void);
     bool DoSkipCommercials(int direction);
@@ -596,6 +605,9 @@
     mutable QString  errorMsg;   ///< Reason why NVP exited with a error
     mutable int errorType;
 
+    // Chapter stuff
+    int jumpchapter;
+
     // Bookmark stuff
     long long bookmarkseek;
     bool      previewFromBookmark;
Index: libs/libmythtv/tv_play.cpp
===================================================================
--- libs/libmythtv/tv_play.cpp	(revision 23097)
+++ libs/libmythtv/tv_play.cpp	(working copy)
@@ -4222,6 +4222,8 @@
     {
         if (isDVD)
             DVDJumpBack(ctx);
+        else if (GetNumChapters(ctx) > 0)
+            DoJumpChapter(ctx, -1);
         else
             DoSeek(ctx, -ctx->jumptime * 60, tr("Jump Back"));
     }
@@ -4229,6 +4231,8 @@
     {
         if (isDVD)
             DVDJumpForward(ctx);
+        else if (GetNumChapters(ctx) > 0)
+            DoJumpChapter(ctx, 1);
         else
             DoSeek(ctx, ctx->jumptime * 60, tr("Jump Ahead"));
     }
@@ -6106,6 +6110,52 @@
     ctx->UnlockPlayingInfo(__FILE__, __LINE__);
 }
 
+int TV::GetNumChapters(PlayerContext *ctx)
+{
+    int num_chapters;
+    ctx->LockDeleteNVP(__FILE__, __LINE__);
+    if (ctx->nvp)
+        num_chapters = ctx->nvp->GetNumChapters();
+    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+
+    return num_chapters;
+}
+
+void TV::DoJumpChapter(PlayerContext *ctx, int direction)
+{
+    NormalSpeed(ctx);
+    StopFFRew(ctx);
+
+    ctx->LockDeleteNVP(__FILE__, __LINE__);
+    bool muted = MuteChannelChange(ctx);
+    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+
+    struct StatusPosInfo posInfo;
+    ctx->CalcNVPSliderPosition(posInfo);
+
+    bool slidertype = false;
+
+    OSD *osd = GetOSDLock(ctx);
+    if (osd)
+    {
+        posInfo.desc = tr("Searching...");
+        if (direction < 0)
+            osd->ShowStatus(posInfo, slidertype, tr("Previous Chapter"), 6);
+        else
+            osd->ShowStatus(posInfo, slidertype, tr("Next Chapter"), 6);
+        SetUpdateOSDPosition(true);
+    }
+    ReturnOSDLock(ctx, osd);
+
+    ctx->LockDeleteNVP(__FILE__, __LINE__);
+    if (ctx->nvp)
+        ctx->nvp->JumpChapter(direction);
+    ctx->UnlockDeleteNVP(__FILE__, __LINE__);
+
+    if (muted)
+        SetMuteTimer(ctx, kMuteTimeout);
+}
+
 void TV::DoSkipCommercials(PlayerContext *ctx, int direction)
 {
     NormalSpeed(ctx);
Index: libs/libmythtv/avformatdecoder.h
===================================================================
--- libs/libmythtv/avformatdecoder.h	(revision 23097)
+++ libs/libmythtv/avformatdecoder.h	(working copy)
@@ -131,6 +131,9 @@
 
     int ScanStreams(bool novideo);
 
+    virtual int GetNumChapters();
+    virtual int GetPrevChapter(int framesPlayed);
+    virtual int GetNextChapter(int framesPlayed);
     virtual bool DoRewind(long long desiredFrame, bool doflush = true);
     virtual bool DoFastForward(long long desiredFrame, bool doflush = true);
 
