summaryrefslogtreecommitdiffstats
path: root/libmpdemux
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2009-04-08 02:43:44 +0300
committerUoti Urpala <uau@glyph.nonexistent.invalid>2009-04-08 02:43:44 +0300
commit53eeb0e41238699fb11701c357941f904338bb25 (patch)
tree965f3585bc690f9b5f654f1022a4c02709911706 /libmpdemux
parentb309b60a0c7230fae29475e8924ff51f107c2563 (diff)
parent96daf7ed5ef96b86f2539164c27155bc830aa2a6 (diff)
downloadmpv-53eeb0e41238699fb11701c357941f904338bb25.tar.bz2
mpv-53eeb0e41238699fb11701c357941f904338bb25.tar.xz
Merge branch 'ordered_chapters'
Diffstat (limited to 'libmpdemux')
-rw-r--r--libmpdemux/demux_demuxers.c3
-rw-r--r--libmpdemux/demux_lavf.c7
-rw-r--r--libmpdemux/demux_mkv.c418
-rw-r--r--libmpdemux/demuxer.c77
-rw-r--r--libmpdemux/demuxer.h26
-rw-r--r--libmpdemux/ebml.h3
6 files changed, 281 insertions, 253 deletions
diff --git a/libmpdemux/demux_demuxers.c b/libmpdemux/demux_demuxers.c
index a5f87e601b..dc04ecffd0 100644
--- a/libmpdemux/demux_demuxers.c
+++ b/libmpdemux/demux_demuxers.c
@@ -8,6 +8,7 @@
#include "stream/stream.h"
#include "demuxer.h"
#include "stheader.h"
+#include "talloc.h"
typedef struct dd_priv {
demuxer_t* vd;
@@ -21,7 +22,7 @@ demuxer_t* new_demuxers_demuxer(demuxer_t* vd, demuxer_t* ad, demuxer_t* sd) {
demuxer_t* ret;
dd_priv_t* priv;
- ret = calloc(1,sizeof(demuxer_t));
+ ret = talloc_zero(NULL, struct demuxer);
priv = malloc(sizeof(dd_priv_t));
priv->vd = vd;
diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c
index e977255fea..cea44dc50f 100644
--- a/libmpdemux/demux_lavf.c
+++ b/libmpdemux/demux_lavf.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
// #include <unistd.h>
#include <limits.h>
+#include <stdbool.h>
#include "config.h"
#include "options.h"
@@ -533,6 +534,8 @@ static demuxer_t* demux_open_lavf(demuxer_t *demuxer){
demuxer->video->id=-2; // audio-only
} //else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;
+ demuxer->accurate_seek = true;
+
return demuxer;
}
@@ -612,6 +615,10 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, float audio
} else {
if (rel_seek_secs < 0) avsflags = AVSEEK_FLAG_BACKWARD;
}
+ if (flags & SEEK_FORWARD)
+ avsflags = 0;
+ else if (flags & SEEK_BACKWARD)
+ avsflags = AVSEEK_FLAG_BACKWARD;
if (flags & SEEK_FACTOR) {
if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE)
return;
diff --git a/libmpdemux/demux_mkv.c b/libmpdemux/demux_mkv.c
index 76a3874723..e9853bc3e4 100644
--- a/libmpdemux/demux_mkv.c
+++ b/libmpdemux/demux_mkv.c
@@ -12,7 +12,9 @@
#include <stdio.h>
#include <ctype.h>
#include <inttypes.h>
+#include <stdbool.h>
+#include "talloc.h"
#include "options.h"
#include "stream/stream.h"
#include "demuxer.h"
@@ -151,8 +153,7 @@ typedef struct mkv_demuxer
mkv_track_t **tracks;
int num_tracks;
- uint64_t tc_scale, cluster_tc, first_tc;
- int has_first_tc;
+ uint64_t tc_scale, cluster_tc;
uint64_t cluster_size;
uint64_t blockgroup_size;
@@ -171,8 +172,6 @@ typedef struct mkv_demuxer
int64_t skip_to_timecode;
int v_skip_to_keyframe, a_skip_to_keyframe;
- int64_t stop_timecode;
-
int last_aid;
int audio_tracks[MAX_A_STREAMS];
} mkv_demuxer_t;
@@ -375,52 +374,67 @@ lzo_fail:
}
-static int
-demux_mkv_read_info (demuxer_t *demuxer)
+static int demux_mkv_read_info(demuxer_t *demuxer)
{
- mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
- stream_t *s = demuxer->stream;
- uint64_t length, l;
- int il;
- uint64_t tc_scale = 1000000;
- long double duration = 0.;
-
- length = ebml_read_length (s, NULL);
- while (length > 0)
- {
- switch (ebml_read_id (s, &il))
- {
+ mkv_demuxer_t *mkv_d = demuxer->priv;
+ stream_t *s = demuxer->stream;
+ uint64_t length, l;
+ int i;
+ uint64_t tc_scale = 1000000;
+ long double duration = 0.;
+
+ length = ebml_read_length(s, NULL);
+ while (length > 0) {
+ uint32_t id = ebml_read_id(s, &i);
+ length -= i;
+ switch (id) {
case MATROSKA_ID_TIMECODESCALE:
- {
- uint64_t num = ebml_read_uint (s, &l);
- if (num == EBML_UINT_INVALID)
- return 1;
- tc_scale = num;
- mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + timecode scale: %"PRIu64"\n",
+ tc_scale = ebml_read_uint(s, &l);
+ length -= l;
+ if (tc_scale == EBML_UINT_INVALID)
+ return 1;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + timecode scale: %"PRIu64"\n",
tc_scale);
break;
- }
case MATROSKA_ID_DURATION:
- {
- long double num = ebml_read_float (s, &l);
- if (num == EBML_FLOAT_INVALID)
- return 1;
- duration = num;
- mp_msg (MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3Lfs\n",
- duration * tc_scale / 1000000000.0);
+ duration = ebml_read_float(s, &l);
+ length -= l;
+ if (duration == EBML_FLOAT_INVALID)
+ return 1;
+ break;
+
+ case MATROSKA_ID_SEGMENTUID:;
+ l = ebml_read_length(s, &i);
+ length -= i;
+ if (l != sizeof(demuxer->matroska_data.segment_uid)) {
+ mp_msg(MSGT_DEMUX, MSGL_INFO,
+ "[mkv] segment uid invalid length %"PRIu64"\n", l);
+ stream_skip(s, l);
+ } else {
+ stream_read(s, demuxer->matroska_data.segment_uid, l);
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + segment uid");
+ for (int i = 0; i < l; i++)
+ mp_msg(MSGT_DEMUX, MSGL_V, " %02x",
+ demuxer->matroska_data.segment_uid[i]);
+ mp_msg(MSGT_DEMUX, MSGL_V, "\n");
+ }
+ length -= l;
break;
- }
default:
- ebml_read_skip (s, &l);
- break;
+ ebml_read_skip(s, &l);
+ length -= l;
+ break;
}
- length -= l + il;
}
- mkv_d->tc_scale = tc_scale;
- mkv_d->duration = duration * tc_scale / 1000000000.0;
- return 0;
+ mkv_d->tc_scale = tc_scale;
+ mkv_d->duration = duration * tc_scale / 1000000000.0;
+ if (duration)
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3fs\n",
+ mkv_d->duration);
+
+ return 0;
}
/**
@@ -1077,140 +1091,175 @@ demux_mkv_read_cues (demuxer_t *demuxer)
return 0;
}
-static int
-demux_mkv_read_chapters (demuxer_t *demuxer)
+static uint64_t read_one_chapter(struct demuxer *demuxer, stream_t *s)
{
- stream_t *s = demuxer->stream;
- uint64_t length, l;
- int il;
-
- if (demuxer->chapters)
- {
- ebml_read_skip (s, NULL);
- return 0;
- }
-
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n");
- length = ebml_read_length (s, NULL);
-
- while (length > 0)
- {
- switch (ebml_read_id (s, &il))
- {
- case MATROSKA_ID_EDITIONENTRY:
- {
- uint64_t len;
- int i;
-
- len = ebml_read_length (s, &i);
- l = len + i;
+ uint64_t len, l;
+ uint64_t start = 0, end = 0;
+ struct matroska_chapter chapter = {};
+ char *name = 0;
+ int i;
+ uint32_t id;
+
+ len = ebml_read_length(s, &i);
+ uint64_t bytes_read = len + i;
+
+ while (len > 0) {
+ id = ebml_read_id(s, &i);
+ len -= i;
+ switch (id) {
+ case MATROSKA_ID_CHAPTERTIMESTART:
+ start = ebml_read_uint(s, &l) / 1000000;
+ len -= l;
+ break;
- while (len > 0)
- {
- uint64_t l;
- int il;
+ case MATROSKA_ID_CHAPTERTIMEEND:
+ end = ebml_read_uint(s, &l) / 1000000;
+ len -= l;
+ break;
- switch (ebml_read_id (s, &il))
- {
- case MATROSKA_ID_CHAPTERATOM:
- {
- uint64_t len, start=0, end=0;
- char* name = 0;
- int i;
- int cid;
+ case MATROSKA_ID_CHAPTERDISPLAY:;
+ uint64_t displaylen = ebml_read_length(s, &i);
+ len -= displaylen + i;
+ while (displaylen > 0) {
+ id = ebml_read_id(s, &i);
+ displaylen -= i;
+ switch (id) {
+ case MATROSKA_ID_CHAPSTRING:
+ name = ebml_read_utf8(s, &l);
+ break;
+ default:
+ ebml_read_skip(s, &l);
+ break;
+ }
+ displaylen -= l;
+ }
+ break;
- len = ebml_read_length (s, &i);
- l = len + i;
+ case MATROSKA_ID_CHAPTERSEGMENTUID:
+ l = ebml_read_length(s, &i);
+ len -= l + i;
+ if (l != sizeof(chapter.segment_uid)) {
+ mp_msg(MSGT_DEMUX, MSGL_INFO,
+ "[mkv] chapter segment uid invalid length %"PRIu64"\n",
+ l);
+ stream_skip(s, l);
+ } else {
+ stream_read(s, chapter.segment_uid, l);
+ chapter.has_segment_uid = true;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter segment uid ");
+ for (int i = 0; i < l; i++)
+ mp_msg(MSGT_DEMUX, MSGL_V, "%02x ", chapter.segment_uid[i]);
+ mp_msg(MSGT_DEMUX, MSGL_V, "\n");
+ }
+ break;
- while (len > 0)
- {
- uint64_t l;
- int il;
+ default:
+ ebml_read_skip(s, &l);
+ len -= l;
+ break;
+ }
+ }
- switch (ebml_read_id (s, &il))
- {
- case MATROSKA_ID_CHAPTERTIMESTART:
- start = ebml_read_uint (s, &l) / 1000000;
- break;
+ if (!name)
+ name = strdup("(unnamed)");
+
+ int cid = demuxer_add_chapter(demuxer, name, start, end);
+ struct matroska_data *m = &demuxer->matroska_data;
+ m->ordered_chapters = talloc_realloc(demuxer, m->ordered_chapters,
+ struct matroska_chapter,
+ m->num_ordered_chapters + 1);
+ chapter.start = start;
+ chapter.end = end;
+ chapter.name = talloc_strdup(m->ordered_chapters, name);
+ // Will be undone later if this is a normal chapter rather than ordered
+ m->ordered_chapters[m->num_ordered_chapters] = chapter;
+ m->num_ordered_chapters++;
+
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter %u from %02d:%02d:%02d."
+ "%03d to %02d:%02d:%02d.%03d, %s\n",
+ cid,
+ (int) (start / 60 / 60 / 1000),
+ (int) ((start / 60 / 1000) % 60),
+ (int) ((start / 1000) % 60),
+ (int) (start % 1000),
+ (int) (end / 60 / 60 / 1000),
+ (int) ((end / 60 / 1000) % 60),
+ (int) ((end / 1000) % 60),
+ (int) (end % 1000), name);
+
+ free(name);
+ return bytes_read;
+}
- case MATROSKA_ID_CHAPTERTIMEEND:
- end = ebml_read_uint (s, &l) / 1000000;
- break;
+static int demux_mkv_read_chapters(struct demuxer *demuxer)
+{
+ stream_t *s = demuxer->stream;
+ uint64_t length, l;
+ int i;
+ uint32_t id;
- 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;
+ if (demuxer->chapters) {
+ ebml_read_skip(s, NULL);
+ return 0;
+ }
- default:
- ebml_read_skip (s, &l);
- break;
- }
- len -= l + il;
- }
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n");
+ length = ebml_read_length(s, NULL);
- 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, %s\n",
- cid,
- (int) (start / 60 / 60 / 1000),
- (int) ((start / 60 / 1000) % 60),
- (int) ((start / 1000) % 60),
- (int) (start % 1000),
- (int) (end / 60 / 60 / 1000),
- (int) ((end / 60 / 1000) % 60),
- (int) ((end / 1000) % 60),
- (int) (end % 1000), name);
-
- free(name);
- break;
- }
+ bool have_edition = false;
+ while (length > 0) {
+ id = ebml_read_id(s, &i);
+ length -= i;
+ switch (id) {
+ case MATROSKA_ID_EDITIONENTRY:
+ if (have_edition) {
+ mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] Multiple edition entries"
+ " - ignoring all but first!\n");
+ ebml_read_skip(s, &l);
+ length -= l;
+ break;
+ }
+ have_edition = true;
+ uint64_t editionlen = ebml_read_length(s, &i);
+ length -= editionlen + i;
+ bool ordered = false;
+ while (editionlen > 0) {
+ id = ebml_read_id(s, &i);
+ editionlen -= i;
+ switch (id) {
+ case MATROSKA_ID_CHAPTERATOM:
+ l = read_one_chapter(demuxer, s);
+ break;
+ case MATROSKA_ID_EDITIONFLAGORDERED:
+ ordered = ebml_read_uint(s, &l);
+ mp_msg(MSGT_DEMUX, MSGL_V,
+ "[mkv] Ordered chapter flag: %d\n", ordered);
+ break;
- default:
- ebml_read_skip (s, &l);
+ default:
+ ebml_read_skip(s, &l);
break;
- }
- len -= l + il;
- }
+ }
+ editionlen -= l;
+ }
+ if (!ordered) {
+ // The chapters should be interpreted as normal ones,
+ // so undo the addition of this information.
+ talloc_free(demuxer->matroska_data.ordered_chapters);
+ demuxer->matroska_data.ordered_chapters = NULL;
+ demuxer->matroska_data.num_ordered_chapters = 0;
+ }
break;
- }
default:
- ebml_read_skip (s, &l);
- break;
+ ebml_read_skip(s, &l);
+ length -= l;
+ break;
}
-
- length -= l + il;
}
- mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing chapters ] ---------\n");
- return 0;
+ mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing chapters ] ---------\n");
+ return 0;
}
static int
@@ -2114,8 +2163,6 @@ demux_mkv_open (demuxer_t *demuxer)
uint64_t num = ebml_read_uint (s, NULL);
if (num == EBML_UINT_INVALID)
return 0;
- mkv_d->first_tc = num * mkv_d->tc_scale / 1000000.0;
- mkv_d->has_first_tc = 1;
}
stream_seek (s, p - 4);
cont = 1;
@@ -2219,22 +2266,6 @@ demux_mkv_open (demuxer_t *demuxer)
}
}
- if (demuxer->chapters)
- {
- for (i=0; i < (int)demuxer->num_chapters; i++)
- {
- demuxer->chapters[i].start -= mkv_d->first_tc;
- demuxer->chapters[i].end -= mkv_d->first_tc;
- }
- if (dvd_last_chapter > 0 && dvd_last_chapter <= demuxer->num_chapters)
- {
- 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;
- }
- }
-
if (s->end_pos == 0 || (mkv_d->indexes == NULL && index_mode < 0))
demuxer->seekable = 0;
else
@@ -2244,6 +2275,8 @@ demux_mkv_open (demuxer_t *demuxer)
demuxer->seekable = 1;
}
+ demuxer->accurate_seek = true;
+
return DEMUXER_TYPE_MATROSKA;
}
@@ -2622,13 +2655,9 @@ handle_block (demuxer_t *demuxer, uint8_t *block, uint64_t length,
return 0;
block += old_length - length;
- tc = ((time*mkv_d->tc_scale+mkv_d->cluster_tc) /1000000.0 - mkv_d->first_tc);
+ tc = ((time*mkv_d->tc_scale+mkv_d->cluster_tc) /1000000.0);
if (tc < 0)
tc = 0;
- if (mkv_d->stop_timecode > 0 && tc > mkv_d->stop_timecode) {
- free(lace_size);
- return -1;
- }
current_pts = tc / 1000.0;
for (i=0; i<mkv_d->num_tracks; i++)
@@ -2851,11 +2880,6 @@ demux_mkv_fill_buffer (demuxer_t *demuxer, demux_stream_t *ds)
uint64_t num = ebml_read_uint (s, &l);
if (num == EBML_UINT_INVALID)
return 0;
- if (!mkv_d->has_first_tc)
- {
- mkv_d->first_tc = num * mkv_d->tc_scale / 1000000.0;
- mkv_d->has_first_tc = 1;
- }
mkv_d->cluster_tc = num * mkv_d->tc_scale;
break;
}
@@ -2911,6 +2935,16 @@ demux_mkv_fill_buffer (demuxer_t *demuxer, demux_stream_t *ds)
static void
demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
{
+ if (!(flags & (SEEK_BACKWARD | SEEK_FORWARD))) {
+ if (flags & SEEK_ABSOLUTE || rel_seek_secs < 0)
+ flags |= SEEK_BACKWARD;
+ else
+ flags |= SEEK_FORWARD;
+ }
+ // Adjust the target a little bit to catch cases where the target position
+ // specifies a keyframe with high, but not perfect, precision.
+ rel_seek_secs += flags & SEEK_FORWARD ? -0.001 : 0.001;
+
free_cached_dps (demuxer);
if (!(flags & SEEK_FACTOR)) /* time in secs */
{
@@ -2965,12 +2999,12 @@ demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int
for (i=0; i < mkv_d->num_cluster_pos; i++)
{
diff = mkv_d->cluster_positions[i] - target_filepos;
- if (rel_seek_secs < 0 && diff < 0 && -diff < min_diff)
+ if (flags & SEEK_BACKWARD && diff < 0 && -diff < min_diff)
{
cluster_pos = mkv_d->cluster_positions[i];
min_diff = -diff;
}
- else if (rel_seek_secs > 0
+ else if (flags & SEEK_FORWARD
&& (diff < 0 ? -1 * diff : diff) < min_diff)
{
cluster_pos = mkv_d->cluster_positions[i];
@@ -2991,17 +3025,17 @@ demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int
for (i=0; i < mkv_d->num_indexes; i++)
if (mkv_d->indexes[i].tnum == seek_id)
{
- diff = target_timecode + mkv_d->first_tc -
+ diff = target_timecode -
(int64_t) mkv_d->indexes[i].timecode * mkv_d->tc_scale / 1000000.0;
- if ((flags & SEEK_ABSOLUTE || target_timecode <= mkv_d->last_pts*1000)) {
- // Absolute seek or seek backward: find the last index
- // position before target time
+ if (flags & SEEK_BACKWARD) {
+ // Seek backward: find the last index position
+ // before target time
if (diff < 0 || diff >= min_diff)
continue;
}
else {
- // Relative seek forward: find the first index position
+ // Seek forward: find the first index position
// after target time. If no such index exists, find last
// position between current position and target time.
if (diff <= 0) {
@@ -3025,8 +3059,10 @@ demux_mkv_seek (demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int
if (demuxer->video->id >= 0)
mkv_d->v_skip_to_keyframe = 1;
- if (rel_seek_secs > 0.0)
+ if (flags & SEEK_FORWARD)
mkv_d->skip_to_timecode = target_timecode;
+ else
+ mkv_d->skip_to_timecode = 0;
mkv_d->a_skip_to_keyframe = 1;
demux_mkv_fill_buffer(demuxer, NULL);
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index e9f577ae65..f84c3d8b87 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -10,6 +10,7 @@
#include "config.h"
#include "options.h"
+#include "talloc.h"
#include "mp_msg.h"
#include "help_mp.h"
#include "m_config.h"
@@ -216,8 +217,7 @@ static const demuxer_desc_t *get_demuxer_desc_from_type(int file_format)
demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
int a_id, int v_id, int s_id, char *filename)
{
- demuxer_t *d = malloc(sizeof(demuxer_t));
- memset(d, 0, sizeof(demuxer_t));
+ struct demuxer *d = talloc_zero(NULL, struct demuxer);
d->stream = stream;
d->stream_pts = MP_NOPTS_VALUE;
d->reference_clock = MP_NOPTS_VALUE;
@@ -390,7 +390,7 @@ void free_demuxer(demuxer_t *demuxer)
}
free(demuxer->attachments);
}
- free(demuxer);
+ talloc_free(demuxer);
}
@@ -1331,31 +1331,19 @@ int demuxer_add_chapter(demuxer_t *demuxer, const char *name, uint64_t start,
* either using the demuxer->chapters structure set by the demuxer
* or asking help to the stream layer (e.g. dvd)
* \param chapter - chapter number wished - 0-based
- * \param mode 0: relative to current main pts, 1: absolute
* \param seek_pts set by the function to the pts to seek to (if demuxer->chapters is set)
- * \param num_chapters number of chapters present (set by this function is param is not null)
* \param chapter_name name of chapter found (set by this function is param is not null)
* \return -1 on error, current chapter if successful
*/
-int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, int mode,
- float *seek_pts, int *num_chapters,
+int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, double *seek_pts,
char **chapter_name)
{
int ris;
- int current, total;
sh_video_t *sh_video = demuxer->video->sh;
sh_audio_t *sh_audio = demuxer->audio->sh;
if (!demuxer->num_chapters || !demuxer->chapters) {
- if (!mode) {
- ris = stream_control(demuxer->stream,
- STREAM_CTRL_GET_CURRENT_CHAPTER, &current);
- if (ris == STREAM_UNSUPPORTED)
- return -1;
- chapter += current;
- }
-
demux_flush(demuxer);
ris = stream_control(demuxer->stream, STREAM_CTRL_SEEK_TO_CHAPTER,
@@ -1375,60 +1363,31 @@ int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, int mode,
// (because e.g. dvds depend on sectors, not on pts)
*seek_pts = -1.0;
- if (num_chapters) {
- if (stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS,
- num_chapters) == STREAM_UNSUPPORTED)
- *num_chapters = 0;
- }
-
if (chapter_name) {
*chapter_name = NULL;
- if (num_chapters && *num_chapters) {
- char *tmp = malloc(16);
- if (tmp) {
- sprintf(tmp, " of %3d", *num_chapters);
- *chapter_name = tmp;
- }
+ int num_chapters;
+ if (stream_control(demuxer->stream, STREAM_CTRL_GET_NUM_CHAPTERS,
+ &num_chapters) == STREAM_UNSUPPORTED)
+ num_chapters = 0;
+ if (num_chapters) {
+ *chapter_name = talloc_size(NULL, 16);
+ sprintf(*chapter_name, " of %3d", num_chapters);
}
}
return ris != STREAM_UNSUPPORTED ? chapter : -1;
} else { // chapters structure is set in the demuxer
- total = demuxer->num_chapters;
-
- if (mode == 1) //absolute seeking
- current = chapter;
- else { //relative seeking
- 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 += chapter;
- }
-
- if (current >= total)
+ if (chapter >= demuxer->num_chapters)
return -1;
- if (current < 0)
- current = 0;
+ if (chapter < 0)
+ chapter = 0;
- *seek_pts = demuxer->chapters[current].start / 1000.0;
+ *seek_pts = demuxer->chapters[chapter].start / 1000.0;
- if (num_chapters)
- *num_chapters = demuxer->num_chapters;
-
- if (chapter_name) {
- if (demuxer->chapters[current].name)
- *chapter_name = strdup(demuxer->chapters[current].name);
- else
- *chapter_name = NULL;
- }
+ if (chapter_name)
+ *chapter_name = talloc_strdup(NULL, demuxer->chapters[chapter].name);
- return current;
+ return chapter;
}
}
diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h
index 4815c8b7d9..544afe8add 100644
--- a/libmpdemux/demuxer.h
+++ b/libmpdemux/demuxer.h
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
#include "stream/stream.h"
@@ -95,6 +96,8 @@ struct MPOpts;
#define SEEK_ABSOLUTE (1 << 0)
#define SEEK_FACTOR (1 << 1)
+#define SEEK_FORWARD (1 << 2)
+#define SEEK_BACKWARD (1 << 3)
#define MP_INPUT_BUFFER_PADDING_SIZE 8
@@ -187,6 +190,19 @@ typedef struct demux_chapter
char* name;
} demux_chapter_t;
+struct matroska_data {
+ unsigned char segment_uid[16];
+ // Ordered chapter information if any
+ struct matroska_chapter {
+ uint64_t start;
+ uint64_t end;
+ bool has_segment_uid;
+ unsigned char segment_uid[16];
+ char *name;
+ } *ordered_chapters;
+ int num_ordered_chapters;
+};
+
typedef struct demux_attachment
{
char* name;
@@ -208,6 +224,9 @@ typedef struct demuxer {
int type; // demuxer type: mpeg PS, mpeg ES, avi, avi-ni, avi-nini, asf
int file_format; // file format: mpeg/avi/asf
int seekable; // flag
+ /* Set if using absolute seeks for small movements is OK (no pts resets
+ * that would make pts ambigious, preferably supports back/forward flags */
+ bool accurate_seek;
//
demux_stream_t *audio; // audio buffer/demuxer
demux_stream_t *video; // video buffer/demuxer
@@ -220,10 +239,12 @@ typedef struct demuxer {
demux_chapter_t* chapters;
int num_chapters;
-
+
demux_attachment_t* attachments;
int num_attachments;
+ struct matroska_data matroska_data;
+
void* priv; // fileformat-dependent data
char** info;
struct MPOpts *opts;
@@ -411,7 +432,8 @@ int demuxer_add_attachment(demuxer_t* demuxer, const char* name,
const char* type, const void* data, size_t size);
int demuxer_add_chapter(demuxer_t* demuxer, const char* name, uint64_t start, uint64_t end);
-int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, int mode, float *seek_pts, int *num_chapters, char **chapter_name);
+int demuxer_seek_chapter(demuxer_t *demuxer, int chapter, double *seek_pts,
+ char **chapter_name);
/// Get current chapter index if available.
int demuxer_get_current_chapter(demuxer_t *demuxer);
diff --git a/libmpdemux/ebml.h b/libmpdemux/ebml.h
index c4d7256d91..345f08b46a 100644
--- a/libmpdemux/ebml.h
+++ b/libmpdemux/ebml.h
@@ -54,6 +54,7 @@
#define MATROSKA_ID_WRITINGAPP 0x5741
#define MATROSKA_ID_MUXINGAPP 0x4D80
#define MATROSKA_ID_DATEUTC 0x4461
+#define MATROSKA_ID_SEGMENTUID 0x73A4
/* ID in the tracks master */
#define MATROSKA_ID_TRACKENTRY 0xAE
@@ -126,11 +127,13 @@
/* IDs in the chapters master */
#define MATROSKA_ID_EDITIONENTRY 0x45B9
+#define MATROSKA_ID_EDITIONFLAGORDERED 0x45DD
#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
+#define MATROSKA_ID_CHAPTERSEGMENTUID 0x6E67
/* IDs in the cluster master */
#define MATROSKA_ID_CLUSTERTIMECODE 0xE7