changeset 19342:4e68a3881201

Add matroska chapter seeking capability.
author eugeni
date Sun, 06 Aug 2006 18:55:34 +0000
parents f6661e33aa60
children 24f2f73f03ca
files DOCS/man/en/mplayer.1 DOCS/tech/slave.txt help/help_mp-en.h input/input.c input/input.h libmpdemux/demux_mkv.c libmpdemux/demuxer.c libmpdemux/demuxer.h libmpdemux/ebml.h mplayer.c
diffstat 10 files changed, 142 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/man/en/mplayer.1	Sun Aug 06 18:02:42 2006 +0000
+++ b/DOCS/man/en/mplayer.1	Sun Aug 06 18:55:34 2006 +0000
@@ -316,6 +316,8 @@
 Take a screenshot.
 .IPs "I"
 Show filename on the OSD.
+.IPs "! and @"
+Seek to the beginning of the previous/next chapter.
 .RE
 .PD 1
 .PP
--- a/DOCS/tech/slave.txt	Sun Aug 06 18:02:42 2006 +0000
+++ b/DOCS/tech/slave.txt	Sun Aug 06 18:55:34 2006 +0000
@@ -177,6 +177,11 @@
         1 is a seek to <value> % in the movie.
         2 is a seek to an absolute position of <value> seconds.
 
+seek_chapter <value> [type]
+    Seek to the start of a chapter.
+        0 is a relative seek of +/- <value> chapters (default)
+        1 is a seek to a chapter #<value>
+
 set_property <property> <value>
     Set a property.
 
--- a/help/help_mp-en.h	Sun Aug 06 18:02:42 2006 +0000
+++ b/help/help_mp-en.h	Sun Aug 06 18:55:34 2006 +0000
@@ -210,6 +210,7 @@
 #define MSGTR_OSDSubDelay "Sub delay: %d ms"
 #define MSGTR_OSDSpeed "Speed: x %6.2f"
 #define MSGTR_OSDosd "OSD: %s"
+#define MSGTR_OSDChapter "Chapter: (%d) %s"
 
 // property values
 #define MSGTR_Enabled "enabled"
--- a/input/input.c	Sun Aug 06 18:02:42 2006 +0000
+++ b/input/input.c	Sun Aug 06 18:55:34 2006 +0000
@@ -146,6 +146,8 @@
   { MP_CMD_SET_PROPERTY, "set_property", 2, { {MP_CMD_ARG_STRING, {0}},  {MP_CMD_ARG_STRING, {0}}, {-1,{0}} } },
   { MP_CMD_GET_PROPERTY, "get_property", 1, { {MP_CMD_ARG_STRING, {0}},  {-1,{0}} } },
   
+  { MP_CMD_SEEK_CHAPTER, "seek_chapter", 1, { {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
+  
   { 0, NULL, 0, {} }
 };
 
@@ -392,6 +394,9 @@
   { { KEY_MUTE, 0 }, "mute" },
           
   { { KEY_CLOSE_WIN, 0 }, "quit" },
+  
+  { { '!', 0 }, "seek_chapter -1" },
+  { { '@', 0 }, "seek_chapter 1" },
 
   { { 0 }, NULL }
 };
--- a/input/input.h	Sun Aug 06 18:02:42 2006 +0000
+++ b/input/input.h	Sun Aug 06 18:55:34 2006 +0000
@@ -70,6 +70,7 @@
 #define MP_CMD_SET_PROPERTY 68
 #define MP_CMD_GET_PROPERTY 69
 #define MP_CMD_OSD_SHOW_PROPERTY_TEXT 70
+#define MP_CMD_SEEK_CHAPTER 71
 
 #define MP_CMD_GUI_EVENTS       5000
 #define MP_CMD_GUI_LOADFILE     5001
--- a/libmpdemux/demux_mkv.c	Sun Aug 06 18:02:42 2006 +0000
+++ b/libmpdemux/demux_mkv.c	Sun Aug 06 18:55:34 2006 +0000
@@ -141,11 +141,6 @@
   uint64_t timecode, filepos;
 } mkv_index_t;
 
-typedef struct mkv_chapter
-{
-  uint64_t start, end;
-} mkv_chapter_t;
-
 typedef struct mkv_attachment
 {
   char* name;
@@ -188,8 +183,6 @@
   int64_t skip_to_timecode;
   int v_skip_to_keyframe, a_skip_to_keyframe;
 
-  mkv_chapter_t *chapters;
-  int num_chapters;
   int64_t stop_timecode;
   
   int last_aid;
@@ -1328,7 +1321,7 @@
   uint64_t length, l;
   int il;
 
-  if (mkv_d->chapters)
+  if (demuxer->chapters)
     {
       ebml_read_skip (s, NULL);
       return 0;
@@ -1359,18 +1352,13 @@
                   case MATROSKA_ID_CHAPTERATOM:
                     {
                       uint64_t len, start=0, end=0;
+                      char* name = 0;
                       int i;
+                      int cid;
 
                       len = ebml_read_length (s, &i);
                       l = len + i;
 
-                      if (mkv_d->chapters == NULL)
-                        mkv_d->chapters = malloc (32*sizeof(*mkv_d->chapters));
-                      else if (!(mkv_d->num_chapters % 32))
-                        mkv_d->chapters = realloc (mkv_d->chapters,
-                                                   (mkv_d->num_chapters + 32)
-                                                   * sizeof(*mkv_d->chapters));
-
                       while (len > 0)
                         {
                           uint64_t l;
@@ -1386,6 +1374,32 @@
                               end = ebml_read_uint (s, &l) / 1000000;
                               break;
 
+                            case MATROSKA_ID_CHAPTERDISPLAY:
+                              {
+                                uint64_t len;
+                                int i;
+
+                                len = ebml_read_length (s, &i);
+                                l = len + i;
+                                while (len > 0)
+                                  {
+                                    uint64_t l;
+                                    int il;
+
+                                    switch (ebml_read_id (s, &il))
+                                      {
+                                        case MATROSKA_ID_CHAPSTRING:
+                                          name = ebml_read_utf8 (s, &l);
+                                          break;
+                                        default:
+                                          ebml_read_skip (s, &l);
+                                          break;
+                                      }
+                                    len -= l + il;
+                                  }
+                              }
+                              break;
+
                             default:
                               ebml_read_skip (s, &l);
                               break;
@@ -1393,12 +1407,15 @@
                           len -= l + il;
                         }
 
-                      mkv_d->chapters[mkv_d->num_chapters].start = start;
-                      mkv_d->chapters[mkv_d->num_chapters].end = end;
+                      if (!name)
+                        name = strdup("(unnamed)");
+                      
+                      cid = demuxer_add_chapter(demuxer, name, start, end);
+                      
                       mp_msg(MSGT_DEMUX, MSGL_V,
                              "[mkv] Chapter %u from %02d:%02d:%02d."
-                             "%03d to %02d:%02d:%02d.%03d\n",
-                             ++mkv_d->num_chapters,
+                             "%03d to %02d:%02d:%02d.%03d, %s\n",
+                             cid,
                              (int) (start / 60 / 60 / 1000),
                              (int) ((start / 60 / 1000) % 60),
                              (int) ((start / 1000) % 60),
@@ -1406,7 +1423,9 @@
                              (int) (end / 60 / 60 / 1000),
                              (int) ((end / 60 / 1000) % 60),
                              (int) ((end / 1000) % 60),
-                             (int) (end % 1000));
+                             (int) (end % 1000), name);
+
+                      free(name);
                       break;
                     }
 
@@ -2581,19 +2600,19 @@
   else
     demuxer->sub->id = -2;
 
-  if (mkv_d->chapters)
+  if (demuxer->chapters)
     {
-      for (i=0; i < (int)mkv_d->num_chapters; i++)
+      for (i=0; i < (int)demuxer->num_chapters; i++)
         {
-          mkv_d->chapters[i].start -= mkv_d->first_tc;
-          mkv_d->chapters[i].end -= mkv_d->first_tc;
+          demuxer->chapters[i].start -= mkv_d->first_tc;
+          demuxer->chapters[i].end -= mkv_d->first_tc;
         }
-      if (dvd_last_chapter > 0 && dvd_last_chapter <= mkv_d->num_chapters)
+      if (dvd_last_chapter > 0 && dvd_last_chapter <= demuxer->num_chapters)
         {
-          if (mkv_d->chapters[dvd_last_chapter-1].end != 0)
-            mkv_d->stop_timecode = mkv_d->chapters[dvd_last_chapter-1].end;
-          else if (dvd_last_chapter + 1 <= mkv_d->num_chapters)
-            mkv_d->stop_timecode = mkv_d->chapters[dvd_last_chapter].start;
+          if (demuxer->chapters[dvd_last_chapter-1].end != 0)
+            mkv_d->stop_timecode = demuxer->chapters[dvd_last_chapter-1].end;
+          else if (dvd_last_chapter + 1 <= demuxer->num_chapters)
+            mkv_d->stop_timecode = demuxer->chapters[dvd_last_chapter].start;
         }
     }
 
@@ -2604,7 +2623,7 @@
       demuxer->movi_start = s->start_pos;
       demuxer->movi_end = s->end_pos;
       demuxer->seekable = 1;
-      if (mkv_d->chapters && dvd_chapter>1 && dvd_chapter<=mkv_d->num_chapters)
+      if (demuxer->chapters && dvd_chapter>1 && dvd_chapter<=demuxer->num_chapters)
         {
           if (!mkv_d->has_first_tc)
             {
@@ -2612,7 +2631,7 @@
               mkv_d->has_first_tc = 1;
             }
           demux_mkv_seek (demuxer,
-                          mkv_d->chapters[dvd_chapter-1].start/1000.0, 0.0, 1);
+                          demuxer->chapters[dvd_chapter-1].start/1000.0, 0.0, 1);
         }
     }
 
@@ -2659,8 +2678,6 @@
         free (mkv_d->indexes);
       if (mkv_d->cluster_positions)
         free (mkv_d->cluster_positions);
-      if (mkv_d->chapters)
-        free (mkv_d->chapters);
       if (mkv_d->parsed_cues)
         free (mkv_d->parsed_cues);
       if (mkv_d->parsed_seekhead)
--- a/libmpdemux/demuxer.c	Sun Aug 06 18:02:42 2006 +0000
+++ b/libmpdemux/demuxer.c	Sun Aug 06 18:55:34 2006 +0000
@@ -287,6 +287,12 @@
     }
     if(demuxer->filename)
       free(demuxer->filename);
+    if (demuxer->chapters) {
+      for (i=0; i<demuxer->num_chapters; i++)
+        if (demuxer->chapters[i].name)
+          free(demuxer->chapters[i].name);
+      free(demuxer->chapters);
+    }
     free(demuxer);
 }
 
@@ -1024,3 +1030,17 @@
       index = demuxer->audio->id;
     return index;
 }
+
+int demuxer_add_chapter(demuxer_t* demuxer, const char* name, uint64_t start, uint64_t end){
+    if (demuxer->chapters == NULL)
+        demuxer->chapters = malloc (32*sizeof(*demuxer->chapters));
+    else if (!(demuxer->num_chapters % 32))
+        demuxer->chapters = realloc (demuxer->chapters, (demuxer->num_chapters + 32) * sizeof(*demuxer->chapters));
+
+    demuxer->chapters[demuxer->num_chapters].start = start;
+    demuxer->chapters[demuxer->num_chapters].end = end;
+    demuxer->chapters[demuxer->num_chapters].name = strdup(name);
+
+    return demuxer->num_chapters ++;
+}
+
--- a/libmpdemux/demuxer.h	Sun Aug 06 18:02:42 2006 +0000
+++ b/libmpdemux/demuxer.h	Sun Aug 06 18:55:34 2006 +0000
@@ -172,6 +172,12 @@
   int (*control)(struct demuxer_st *demuxer, int cmd, void *arg); ///< Optional
 } demuxer_desc_t;
 
+typedef struct demux_chapter_s
+{
+  uint64_t start, end;
+  char* name;
+} demux_chapter_t;
+
 typedef struct demuxer_st {
   demuxer_desc_t *desc;  ///< Demuxer description structure
   off_t filepos; // input stream current pos.
@@ -192,6 +198,9 @@
   void* a_streams[MAX_A_STREAMS]; // audio streams (sh_audio_t)
   void* v_streams[MAX_V_STREAMS]; // video sterams (sh_video_t)
   char s_streams[32];   // dvd subtitles (flag)
+
+  demux_chapter_t* chapters;
+  int num_chapters;
   
   void* priv;  // fileformat-dependent data
   char** info;
@@ -370,3 +379,6 @@
 
 extern void demuxer_help(void);
 extern int get_demuxer_type_from_name(char *demuxer_name, int *force);
+
+int demuxer_add_chapter(demuxer_t* demuxer, const char* name, uint64_t start, uint64_t end);
+
--- a/libmpdemux/ebml.h	Sun Aug 06 18:02:42 2006 +0000
+++ b/libmpdemux/ebml.h	Sun Aug 06 18:55:34 2006 +0000
@@ -128,6 +128,8 @@
 #define MATROSKA_ID_CHAPTERATOM          0xB6
 #define MATROSKA_ID_CHAPTERTIMESTART     0x91
 #define MATROSKA_ID_CHAPTERTIMEEND       0x92
+#define MATROSKA_ID_CHAPTERDISPLAY       0x80
+#define MATROSKA_ID_CHAPSTRING           0x85
 
 /* IDs in the cluster master */
 #define MATROSKA_ID_CLUSTERTIMECODE      0xE7
--- a/mplayer.c	Sun Aug 06 18:02:42 2006 +0000
+++ b/mplayer.c	Sun Aug 06 18:55:34 2006 +0000
@@ -4807,6 +4807,50 @@
     case MP_CMD_KEYDOWN_EVENTS : {
 		mplayer_put_key(cmd->args[0].v.i);
     } break;
+    case MP_CMD_SEEK_CHAPTER : {
+        int seek = cmd->args[0].v.i;
+        int abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
+        int total;
+        int current;
+
+        if (!demuxer->num_chapters || !demuxer->chapters) {
+            if (seek > 0) {
+                abs_seek_pos = 0;
+                rel_seek_secs = 1000000000.;
+            } else
+                set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, MSGTR_OSDChapter, 0, MSGTR_Unknown);
+            break;
+        }
+
+        total = demuxer->num_chapters;
+
+        if (abs) {
+            current = seek;
+        } else {
+            uint64_t now;
+            now = (sh_video ? sh_video->pts : (sh_audio ? sh_audio->pts : 0.)) * 1000 + .5;
+
+            for (current = total - 1; current >= 0; --current) {
+                demux_chapter_t* chapter = demuxer->chapters + current;
+                if (chapter->start <= now)
+                    break;
+            }
+            current += seek;
+        }
+        
+        if (current < 0) current = 0;
+        if (current >= total) {
+            current = total - 1;
+            abs_seek_pos = 0;
+            rel_seek_secs = 1000000000.;
+        } else {
+            abs_seek_pos = 1;
+            rel_seek_secs = demuxer->chapters[current].start / 1000.;
+        }
+
+        set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, MSGTR_OSDChapter,
+                current, demuxer->chapters[current].name);
+    } break;
     default : {
 #ifdef HAVE_NEW_GUI
       if ( ( use_gui )&&( cmd->id > MP_CMD_GUI_EVENTS ) ) guiGetEvent( guiIEvent,(char *)cmd->id );