diff options
Diffstat (limited to 'libmpdemux')
-rw-r--r-- | libmpdemux/demux_demuxers.c | 3 | ||||
-rw-r--r-- | libmpdemux/demux_lavf.c | 7 | ||||
-rw-r--r-- | libmpdemux/demux_mkv.c | 418 | ||||
-rw-r--r-- | libmpdemux/demuxer.c | 77 | ||||
-rw-r--r-- | libmpdemux/demuxer.h | 26 | ||||
-rw-r--r-- | libmpdemux/ebml.h | 3 |
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, ¤t); - 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 |