diff options
-rw-r--r-- | DOCS/man/en/mplayer.1 | 20 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | cfg-mplayer.h | 9 | ||||
-rw-r--r-- | command.c | 58 | ||||
-rw-r--r-- | defaultopts.c | 5 | ||||
-rw-r--r-- | libmpcodecs/vf_ass.c | 1 | ||||
-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 | ||||
-rw-r--r-- | libvo/vo_gl.c | 1 | ||||
-rw-r--r-- | libvo/vo_gl2.c | 2 | ||||
-rw-r--r-- | libvo/vo_vdpau.c | 1 | ||||
-rw-r--r-- | libvo/vo_x11.c | 1 | ||||
-rw-r--r-- | libvo/vo_xv.c | 1 | ||||
-rw-r--r-- | libvo/x11_common.c | 6 | ||||
-rw-r--r-- | mencoder.c | 6 | ||||
-rw-r--r-- | mp_core.h | 38 | ||||
-rw-r--r-- | mp_osd.h | 1 | ||||
-rw-r--r-- | mpcommon.c | 7 | ||||
-rw-r--r-- | mpcommon.h | 3 | ||||
-rw-r--r-- | mplayer.c | 465 | ||||
-rw-r--r-- | mplayer.h | 1 | ||||
-rw-r--r-- | options.h | 4 | ||||
-rw-r--r-- | osdep/findfiles.c | 97 | ||||
-rw-r--r-- | osdep/findfiles.h | 2 |
28 files changed, 906 insertions, 358 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1 index cf0bf92963..db32b3ad5c 100644 --- a/DOCS/man/en/mplayer.1 +++ b/DOCS/man/en/mplayer.1 @@ -865,10 +865,12 @@ Enqueue files given on the command line in the playlist instead of playing them immediately. . .TP -.B \-fixed\-vo -Enforces a fixed video system for multiple files (one (un)initialization for -all files). +.B \-nofixed\-vo +\-fixed\-vo enforces a fixed video system for multiple files (one +(un)initialization for all files). Therefore only one window will be opened for all files. +Now enabled by default, use \-nofixed\-vo to disable and create a new window +whenever the video stream changes. Currently the following drivers are fixed-vo compliant: gl, gl2, mga, svga, x11, xmga, xv, xvidix and dfbmga. . @@ -1069,6 +1071,11 @@ Turns off LIRC support. .B \-nomouseinput Disable mouse button press/\:release input (mozplayerxp's context menu relies on this option). +.TP +.B \-noorderedchapters +Disable support for Matroska ordered chapters. +MPlayer will not load or search for video segments from other files, +and will also ignore any chapter order specified for the main file. . .TP .B \-rtc (RTC only) @@ -3055,6 +3062,13 @@ VESA framebuffer does not support mode changing. Override framebuffer mode configuration file (default: /etc/\:fb.modes). . .TP +.B \-force\-window\-position +Forcefully move MPlayer's video output window to default location whenever +there is a change in video parameters, video stream or file. +This used to be the default behavior. +Currently only affects X11 VOs. +. +.TP .B \-fs (also see \-zoom) Fullscreen playback (centers movie, and paints black bands around it). Not supported by all video output drivers. @@ -213,6 +213,7 @@ SRCS_COMMON = asxparser.c \ libmpdemux/yuv4mpeg_ratio.c \ libvo/osd.c \ libvo/sub.c \ + osdep/findfiles.c \ osdep/$(GETCH) \ osdep/$(TIMER) \ stream/open.c \ diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 5fe0bff69c..7b2335d776 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -160,6 +160,8 @@ const m_option_t mplayer_opts[]={ OPT_INTRANGE("screenh", vo_screenheight, CONF_OLD, 0, 4096), // Geometry string {"geometry", &vo_geometry, CONF_TYPE_STRING, 0, 0, 0, NULL}, + OPT_FLAG_ON("force-window-position", force_window_position, 0), + OPT_FLAG_OFF("noforce-window-position", force_window_position, 0), // set aspect ratio of monitor - useful for 16:9 TV-out OPT_FLOATRANGE("monitoraspect", force_monitor_aspect, 0, 0.0, 9.0), OPT_FLOATRANGE("monitorpixelaspect", monitor_pixel_aspect, 0, 0.2, 9.0), @@ -240,8 +242,8 @@ const m_option_t mplayer_opts[]={ {"crash-debug", &crash_debug, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL}, {"nocrash-debug", &crash_debug, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL}, #endif - {"osdlevel", &osd_level, CONF_TYPE_INT, CONF_RANGE, 0, 3, NULL}, - {"osd-duration", &osd_duration, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL}, + OPT_INTRANGE("osdlevel", osd_level, 0, 0, 3), + OPT_INTRANGE("osd-duration", osd_duration, 0, 0, 3600000), #ifdef CONFIG_MENU {"menu", &use_menu, CONF_TYPE_FLAG, CONF_GLOBAL, 0, 1, NULL}, {"nomenu", &use_menu, CONF_TYPE_FLAG, CONF_GLOBAL, 1, 0, NULL}, @@ -309,6 +311,9 @@ const m_option_t mplayer_opts[]={ OPT_INTRANGE("loop", loop_times, 0, -1, 10000), {"playlist", NULL, CONF_TYPE_STRING, 0, 0, 0, NULL}, + OPT_FLAG_ON("ordered-chapters", ordered_chapters, 0), + OPT_FLAG_OFF("noordered-chapters", ordered_chapters, 0), + // a-v sync stuff: OPT_FLAG_ON("correct-pts", user_correct_pts, 0), OPT_FLAG_OFF("nocorrect-pts", user_correct_pts, 0), @@ -5,6 +5,7 @@ #include <stdbool.h> #include "config.h" +#include "talloc.h" #include "command.h" #include "input/input.h" #include "stream/stream.h" @@ -172,7 +173,7 @@ static void log_sub(struct MPContext *mpctx) static int mp_property_osdlevel(m_option_t *prop, int action, void *arg, MPContext *mpctx) { - return m_property_choice(prop, action, arg, &osd_level); + return m_property_choice(prop, action, arg, &mpctx->opts.osd_level); } /// Loop (RW) @@ -385,14 +386,13 @@ static int mp_property_time_pos(m_option_t *prop, int action, static int mp_property_chapter(m_option_t *prop, int action, void *arg, MPContext *mpctx) { + struct MPOpts *opts = &mpctx->opts; int chapter = -1; - float next_pts = 0; - int chapter_num; int step_all; char *chapter_name = NULL; if (mpctx->demuxer) - chapter = demuxer_get_current_chapter(mpctx->demuxer); + chapter = get_current_chapter(mpctx); if (chapter < 0) return M_PROPERTY_UNAVAILABLE; @@ -405,7 +405,7 @@ static int mp_property_chapter(m_option_t *prop, int action, void *arg, case M_PROPERTY_PRINT: { if (!arg) return M_PROPERTY_ERROR; - chapter_name = demuxer_chapter_display_name(mpctx->demuxer, chapter); + chapter_name = chapter_display_name(mpctx, chapter); if (!chapter_name) return M_PROPERTY_UNAVAILABLE; *(char **) arg = chapter_name; @@ -430,26 +430,27 @@ static int mp_property_chapter(m_option_t *prop, int action, void *arg, default: return M_PROPERTY_NOT_IMPLEMENTED; } + + double next_pts = 0; + chapter = seek_chapter(mpctx, chapter, &next_pts, &chapter_name); mpctx->rel_seek_secs = 0; mpctx->abs_seek_pos = 0; - chapter = demuxer_seek_chapter(mpctx->demuxer, chapter, 1, - &next_pts, &chapter_num, &chapter_name); if (chapter >= 0) { if (next_pts > -1.0) { mpctx->abs_seek_pos = SEEK_ABSOLUTE; mpctx->rel_seek_secs = next_pts; } if (chapter_name) - set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, + set_osd_msg(OSD_MSG_TEXT, 1, opts->osd_duration, MSGTR_OSDChapter, chapter + 1, chapter_name); } else if (step_all > 0) mpctx->rel_seek_secs = 1000000000.; else - set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, + set_osd_msg(OSD_MSG_TEXT, 1, opts->osd_duration, MSGTR_OSDChapter, 0, MSGTR_Unknown); if (chapter_name) - free(chapter_name); + talloc_free(chapter_name); return M_PROPERTY_OK; } @@ -468,6 +469,7 @@ static int mp_property_chapters(m_option_t *prop, int action, void *arg, static int mp_property_angle(m_option_t *prop, int action, void *arg, MPContext *mpctx) { + struct MPOpts *opts = &mpctx->opts; int angle = -1; int angles; char *angle_name = NULL; @@ -519,7 +521,7 @@ static int mp_property_angle(m_option_t *prop, int action, void *arg, return M_PROPERTY_NOT_IMPLEMENTED; } angle = demuxer_set_angle(mpctx->demuxer, angle); - set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, + set_osd_msg(OSD_MSG_TEXT, 1, opts->osd_duration, MSGTR_OSDAngle, angle, angles); if (angle_name) free(angle_name); @@ -1027,6 +1029,7 @@ static int mp_property_fullscreen(m_option_t *prop, int action, void *arg, #endif if (mpctx->video_out->config_ok) vo_control(mpctx->video_out, VOCTRL_FULLSCREEN, 0); + mpctx->opts.fullscreen = vo_fs; return M_PROPERTY_OK; default: return m_property_flag(prop, action, arg, &vo_fs); @@ -1541,7 +1544,7 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, d_sub->id = opts->sub_id; } #endif - update_subtitles(mpctx->sh_video, d_sub, 1); + update_subtitles(mpctx->sh_video, d_sub, 0, 1); return M_PROPERTY_OK; } @@ -2224,7 +2227,7 @@ static struct { /// set/adjust or toggle command int toggle; /// progressbar type - int osd_progbar; + int osd_progbar; // -1 is special value for seek indicators /// osd msg id if it must be shared int osd_id; /// osd msg template @@ -2232,7 +2235,7 @@ static struct { } set_prop_cmd[] = { // general { "loop", MP_CMD_LOOP, 0, 0, -1, MSGTR_LoopStatus }, - { "chapter", MP_CMD_SEEK_CHAPTER, 0, 0, -1, NULL }, + { "chapter", MP_CMD_SEEK_CHAPTER, 0, -1, -1, NULL }, { "angle", MP_CMD_SWITCH_ANGLE, 0, 0, -1, NULL }, { "pause", MP_CMD_PAUSE, 0, 0, -1, NULL }, // audio @@ -2284,6 +2287,7 @@ static struct { /// Handle commands that set a property. static int set_property_command(MPContext *mpctx, mp_cmd_t *cmd) { + struct MPOpts *opts = &mpctx->opts; int i, r; m_option_t* prop; const char *pname; @@ -2313,7 +2317,9 @@ static int set_property_command(MPContext *mpctx, mp_cmd_t *cmd) if (r <= 0) return 1; - if (set_prop_cmd[i].osd_progbar) { + if (set_prop_cmd[i].osd_progbar == -1) + mpctx->add_osd_seek_info = true; + else if (set_prop_cmd[i].osd_progbar) { if (prop->type == CONF_TYPE_INT) { if (mp_property_do(pname, M_PROPERTY_GET, &r, mpctx) > 0) set_osd_bar(mpctx, set_prop_cmd[i].osd_progbar, @@ -2334,7 +2340,7 @@ static int set_property_command(MPContext *mpctx, mp_cmd_t *cmd) if (val) { set_osd_msg(set_prop_cmd[i].osd_id >= 0 ? set_prop_cmd[i].osd_id : OSD_MSG_PROPERTY + i, - 1, osd_duration, set_prop_cmd[i].osd_msg, val); + 1, opts->osd_duration, set_prop_cmd[i].osd_msg, val); free(val); } } @@ -2376,13 +2382,13 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) struct MPOpts *opts = &mpctx->opts; sh_audio_t * const sh_audio = mpctx->sh_audio; sh_video_t * const sh_video = mpctx->sh_video; + int osd_duration = opts->osd_duration; if (!set_property_command(mpctx, cmd)) switch (cmd->id) { case MP_CMD_SEEK:{ float v; int abs; - if (sh_video) - mpctx->osd_show_percentage = sh_video->fps; + mpctx->add_osd_seek_info = true; v = cmd->args[0].v.f; abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0; if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */ @@ -2620,18 +2626,18 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) int v = cmd->args[0].v.i; int max = (term_osd && !sh_video) ? MAX_TERM_OSD_LEVEL : MAX_OSD_LEVEL; - if (osd_level > max) - osd_level = max; + if (opts->osd_level > max) + opts->osd_level = max; if (v < 0) - osd_level = (osd_level + 1) % (max + 1); + opts->osd_level = (opts->osd_level + 1) % (max + 1); else - osd_level = v > max ? max : v; + opts->osd_level = v > max ? max : v; /* Show OSD state when disabled, but not when an explicit argument is given to the OSD command, i.e. in slave mode. */ - if (v == -1 && osd_level <= 1) + if (v == -1 && opts->osd_level <= 1) set_osd_msg(OSD_MSG_OSD_STATUS, 0, osd_duration, MSGTR_OSDosd, - osd_level ? MSGTR_OSDenabled : + opts->osd_level ? MSGTR_OSDenabled : MSGTR_OSDdisabled); else rm_osd_msg(OSD_MSG_OSD_STATUS); @@ -3180,7 +3186,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) pointer_y = (int) (dy * (double) sh_video->disp_h); mp_dvdnav_update_mouse_pos(mpctx->stream, pointer_x, pointer_y, &button); - if (osd_level > 1 && button > 0) + if (opts->osd_level > 1 && button > 0) set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, "Selected button number %d", button); } @@ -3207,7 +3213,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) command = mp_dvdnav_bindings[i].cmd; mp_dvdnav_handle_input(mpctx->stream,command,&button); - if (osd_level > 1 && button > 0) + if (opts->osd_level > 1 && button > 0) set_osd_msg(OSD_MSG_TEXT, 1, osd_duration, "Selected button number %d", button); } diff --git a/defaultopts.c b/defaultopts.c index fd53979d80..53c02301ac 100644 --- a/defaultopts.c +++ b/defaultopts.c @@ -9,7 +9,7 @@ void set_default_mplayer_options(struct MPOpts *opts) *opts = (const struct MPOpts){ .audio_driver_list = NULL, .video_driver_list = NULL, - .fixed_vo = 0, + .fixed_vo = 1, .monitor_pixel_aspect = 1.0, .vo_panscanrange = 1.0, .vo_gamma_gamma = 1000, @@ -17,7 +17,10 @@ void set_default_mplayer_options(struct MPOpts *opts) .vo_gamma_contrast = 1000, .vo_gamma_saturation = 1000, .vo_gamma_hue = 1000, + .osd_level = 1, + .osd_duration = 1000, .loop_times = -1, + .ordered_chapters = 1, .user_correct_pts = -1, .key_fifo_size = 7, .doubleclick_time = 300, diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 30bdcb0149..c6c2a92423 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -373,6 +373,7 @@ static void uninit(struct vf_instance* vf) free(vf->priv->planes[1]); free(vf->priv->planes[2]); free(vf->priv->line_limits); + free(vf->priv); } static const unsigned int fmt_list[]={ 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. |