summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreugeni <eugeni@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-08-06 18:55:34 +0000
committereugeni <eugeni@b3059339-0415-0410-9bf9-f77b7e298cf2>2006-08-06 18:55:34 +0000
commit1de0c3327d10a43ff3532be7e92c3160c52d55c8 (patch)
tree3530f1fc5b4e87782fbf839dc863b616c779a052
parentd6f16f68897cf2fe11f9ac02fe5ba1dc58c4842e (diff)
downloadmpv-1de0c3327d10a43ff3532be7e92c3160c52d55c8.tar.bz2
mpv-1de0c3327d10a43ff3532be7e92c3160c52d55c8.tar.xz
Add matroska chapter seeking capability.
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19348 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r--DOCS/man/en/mplayer.12
-rw-r--r--DOCS/tech/slave.txt5
-rw-r--r--help/help_mp-en.h1
-rw-r--r--input/input.c5
-rw-r--r--input/input.h1
-rw-r--r--libmpdemux/demux_mkv.c83
-rw-r--r--libmpdemux/demuxer.c20
-rw-r--r--libmpdemux/demuxer.h12
-rw-r--r--libmpdemux/ebml.h2
-rw-r--r--mplayer.c44
10 files changed, 142 insertions, 33 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index f8470b067a..d3ca2837c7 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -316,6 +316,8 @@ Set start or end of an EDL skip and write it out to the given file.
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
diff --git a/DOCS/tech/slave.txt b/DOCS/tech/slave.txt
index 4a1fe627c8..51346d870b 100644
--- a/DOCS/tech/slave.txt
+++ b/DOCS/tech/slave.txt
@@ -177,6 +177,11 @@ seek <value> [type]
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.
diff --git a/help/help_mp-en.h b/help/help_mp-en.h
index e87237d8dd..3cae8360fa 100644
--- a/help/help_mp-en.h
+++ b/help/help_mp-en.h
@@ -210,6 +210,7 @@ static char help_text[]=
#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"
diff --git a/input/input.c b/input/input.c
index 2da5353bfa..5f331310ab 100644
--- a/input/input.c
+++ b/input/input.c
@@ -146,6 +146,8 @@ static mp_cmd_t mp_cmds[] = {
{ 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 @@ static mp_cmd_bind_t def_cmd_binds[] = {
{ { KEY_MUTE, 0 }, "mute" },
{ { KEY_CLOSE_WIN, 0 }, "quit" },
+
+ { { '!', 0 }, "seek_chapter -1" },
+ { { '@', 0 }, "seek_chapter 1" },
{ { 0 }, NULL }
};
diff --git a/input/input.h b/input/input.h
index 5fe9a88121..4d83d1b113 100644
--- a/input/input.h
+++ b/input/input.h
@@ -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
diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c
index 8c29dbb362..e60b7a8c04 100644
--- a/libmpdemux/demux_mkv.c
+++ b/libmpdemux/demux_mkv.c
@@ -141,11 +141,6 @@ typedef struct mkv_index
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 @@ typedef struct mkv_demuxer
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 @@ demux_mkv_read_chapters (demuxer_t *demuxer)
uint64_t length, l;
int il;
- if (mkv_d->chapters)
+ if (demuxer->chapters)
{
ebml_read_skip (s, NULL);
return 0;
@@ -1359,18 +1352,13 @@ demux_mkv_read_chapters (demuxer_t *demuxer)
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 @@ demux_mkv_read_chapters (demuxer_t *demuxer)
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 @@ demux_mkv_read_chapters (demuxer_t *demuxer)
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 @@ demux_mkv_read_chapters (demuxer_t *demuxer)
(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 @@ demux_mkv_open (demuxer_t *demuxer)
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 @@ demux_mkv_open (demuxer_t *demuxer)
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 @@ demux_mkv_open (demuxer_t *demuxer)
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 @@ demux_close_mkv (demuxer_t *demuxer)
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)
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index 1432dac7aa..5a97f35ffb 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -287,6 +287,12 @@ skip_streamfree:
}
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 @@ int demuxer_switch_audio(demuxer_t *demuxer, int index){
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 ++;
+}
+
diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h
index de49d8273b..5cbce24259 100644
--- a/libmpdemux/demuxer.h
+++ b/libmpdemux/demuxer.h
@@ -172,6 +172,12 @@ typedef struct demuxers_desc_st {
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 @@ typedef struct demuxer_st {
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 int demuxer_type_by_filename(char* filename);
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);
+
diff --git a/libmpdemux/ebml.h b/libmpdemux/ebml.h
index 3874f89b91..12fd4bee2f 100644
--- a/libmpdemux/ebml.h
+++ b/libmpdemux/ebml.h
@@ -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
diff --git a/mplayer.c b/mplayer.c
index 70949e1662..d5e63b5052 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -4807,6 +4807,50 @@ if(step_sec>0) {
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 );