aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Uoti Urpala <uau@glyph.nonexistent.invalid>2010-12-20 19:17:43 +0200
committerGravatar Uoti Urpala <uau@glyph.nonexistent.invalid>2010-12-20 19:17:43 +0200
commit0afb326035e66663a90c4609f21560ce772e9718 (patch)
tree07f443e2bd39745ac7430cff9534529958be9c53
parent4a26b4c024498c9b1be4723121d86e0c2b386ed2 (diff)
parent5bb2f9787f557bd91d5eb9021238ed7b131d5fa9 (diff)
Merge branch 'hr-seek'
* hr-seek: input: add default keybindings Shift+[arrow] for small exact seeks input: support bindings with modifier keys for X input core: audio: make ogg missing audio timing workaround more complex core: add support for precise non-keyframe-limited seeks core: add struct for queued seek info commands: add generic option -> property wrapper options: add "choice" option type, use for -pts-association-mode core: remove looping in update_video(), modify command handling a bit core: seek: use accurate seek mode with audio-only files core: avoid using sh_video->pts as "current pts" libvo: register X11 connection fd in input event system core: timing: add special handling of long frame intervals core: move central play loop to a separate function Conflicts: DOCS/tech/slave.txt
-rw-r--r--DOCS/man/en/mplayer.134
-rw-r--r--DOCS/tech/slave.txt15
-rw-r--r--cfg-mplayer.h5
-rw-r--r--command.c91
-rw-r--r--etc/input.conf9
-rw-r--r--input/input.c143
-rw-r--r--libvo/video_out.c24
-rw-r--r--libvo/video_out.h2
-rw-r--r--libvo/vo_xv.c16
-rw-r--r--libvo/x11_common.c22
-rw-r--r--libvo/x11_common.h2
-rw-r--r--m_config.c4
-rw-r--r--m_option.c44
-rw-r--r--m_option.h14
-rw-r--r--mp_core.h22
-rw-r--r--mplayer.c829
-rw-r--r--options.h1
-rw-r--r--osdep/keycodes.h6
18 files changed, 801 insertions, 482 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index be9d8cf3e1..01e48d33d9 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -206,8 +206,12 @@ See the \-input option for ways to customize it.
.RS
.IPs "<\- and \->"
Seek backward/\:forward 10 seconds.
+Shift+arrow does a 1 second exact seek (see \-hr\-seek; currently modifier
+keys like shift only work if used in an X output window).
.IPs "up and down"
Seek forward/\:backward 1 minute.
+Shift+arrow does a 5 second exact seek (see \-hr\-seek; currently modifier
+keys like shift only work if used in an X output window).
.IPs "pgup and pgdown"
Seek forward/\:backward 10 minutes.
.IPs "[ and ]"
@@ -909,6 +913,27 @@ mplayer \-heartbeat\-cmd "gnome\-screensaver\-command \-p" file
.PD 1
.
.TP
+.B \-hr\-seek off|absolute|always
+Select when to use precise seeks that are not limited to keyframes.
+Such seeks require decoding video from the previous keyframe up to the target
+position and so can take some time depending on decoding performance.
+For some video formats precise seeks are disabled. This option selects the
+default choice to use for seeks; it's possible to explicitly override that
+default in the definition of key bindings and in slave mode commands.
+.PD 0
+.RSs
+.IPs off
+Never use precise seeks.
+.IPs absolute
+Use precise seeks if the seek is to an absolute position in the file,
+such as a chapter seek, but not for relative seeks like the default
+behavior of arrow keys (default).
+.IPs always
+Use precise seeks whenever possible.
+.RE
+.PD 1
+.
+.TP
.B \-identify
Shorthand for \-msglevel identify=4.
Show file parameters in an easily parseable format.
@@ -1076,16 +1101,17 @@ 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 \-pts\-association\-mode <mode number>
+.B \-pts\-association\-mode auto|decode|sort
Select the method used to determine which container packet timestamp
corresponds to a particular output frame from the video decoder.
+Normally you shouldn't need to change this option.
.PD 0
.RSs
-.IPs 0
+.IPs auto
Try to pick a working mode from the ones below automatically (default)
-.IPs 1
+.IPs decoder
Use decoder reordering functionality.
-.IPs 2
+.IPs sort
Maintain a buffer of unused pts values and use the lowest value for the frame.
.RE
.PD 1
diff --git a/DOCS/tech/slave.txt b/DOCS/tech/slave.txt
index 1dc9e23aa4..d95ef41d84 100644
--- a/DOCS/tech/slave.txt
+++ b/DOCS/tech/slave.txt
@@ -269,11 +269,16 @@ radio_step_channel <-1|1>
radio_step_freq <value>
Tune frequency by the <value> (positive - up, negative - down).
-seek <value> [type]
+seek <value> [type] [hr-seek]
Seek to some place in the movie.
- 0 is a relative seek of +/- <value> seconds (default).
- 1 is a seek to <value> % in the movie.
- 2 is a seek to an absolute position of <value> seconds.
+ type = 0 is a relative seek of +/- <value> seconds (default).
+ type = 1 is a seek to <value> % in the movie.
+ type = 2 is a seek to an absolute position of <value> seconds.
+ The hr-seek parameter controls whether to use precise seeks (not limited
+ to keyframe positions in video).
+ hr-seek = 0 means use default set with option -hr-seek (default).
+ hr-seek = 1 means force precise seek if possible.
+ hr-seek = -1 means force non-precise seek.
seek_chapter <value> [type]
Seek to the start of a chapter.
@@ -515,6 +520,8 @@ name type min max get set step comment
osdlevel int 0 3 X X X as -osdlevel
speed float 0.01 100 X X X as -speed
loop int -1 X X X as -loop
+hr_seek string X X X as -hr-seek
+pts_association_mode string X X X as -pts-association-mode
pause flag 0 1 X 1 if paused
filename string X file playing wo path
path string X file playing
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index be52df881a..7f0ee1f729 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -309,8 +309,11 @@ const m_option_t mplayer_opts[]={
// a-v sync stuff:
OPT_MAKE_FLAGS("correct-pts", user_correct_pts, 0),
- OPT_INTRANGE("pts-association-mode", user_pts_assoc_mode, 0, 0, 2),
+ OPT_CHOICE("pts-association-mode", user_pts_assoc_mode, 0,
+ ({"auto", 0}, {"decoder", 1}, {"sort", 2})),
OPT_MAKE_FLAGS("initial-audio-sync", initial_audio_sync, 0),
+ OPT_CHOICE("hr-seek", hr_seek, 0,
+ ({"off", -1}, {"absolute", 0}, {"always", 1}, {"on", 1})),
OPT_FLAG_CONSTANTS("noautosync", autosync, 0, 0, -1),
OPT_INTRANGE("autosync", autosync, 0, 0, 10000),
diff --git a/command.c b/command.c
index b490410373..4408a584a6 100644
--- a/command.c
+++ b/command.c
@@ -34,6 +34,7 @@
#include "libvo/sub.h"
#include "m_option.h"
#include "m_property.h"
+#include "m_config.h"
#include "metadata.h"
#include "libmpcodecs/vf.h"
#include "libmpcodecs/vd.h"
@@ -226,6 +227,39 @@ static void log_sub(struct MPContext *mpctx)
/// \ingroup Properties
///@{
+static int mp_property_generic_option(struct m_option *prop, int action,
+ void *arg, MPContext *mpctx)
+{
+ char *optname = prop->priv;
+ const struct m_option *opt = m_config_get_option(mpctx->mconfig, optname);
+ void *valptr = m_option_get_ptr(opt, &mpctx->opts);
+
+ switch (action) {
+ case M_PROPERTY_GET_TYPE:
+ *(const struct m_option **)arg = opt;
+ return M_PROPERTY_OK;
+ case M_PROPERTY_GET:
+ m_option_copy(opt, arg, valptr);
+ return M_PROPERTY_OK;
+ case M_PROPERTY_SET:
+ m_option_copy(opt, valptr, arg);
+ return M_PROPERTY_OK;
+ case M_PROPERTY_STEP_UP:
+ if (opt->type == &m_option_type_choice) {
+ int v = *(int *) valptr;
+ int best = v;
+ struct m_opt_choice_alternatives *alt;
+ for (alt = opt->priv; alt->name; alt++)
+ if ((unsigned) alt->value - v - 1 < (unsigned) best - v - 1)
+ best = alt->value;
+ *(int *) valptr = best;
+ return M_PROPERTY_OK;
+ }
+ break;
+ }
+ return M_PROPERTY_NOT_IMPLEMENTED;
+}
+
/// OSD level (RW)
static int mp_property_osdlevel(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
@@ -418,8 +452,7 @@ static int mp_property_percent_pos(m_option_t *prop, int action,
return m_property_int_ro(prop, action, arg, get_percent_pos(mpctx));
}
- mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
- mpctx->rel_seek_secs = pos / 100.0;
+ queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0);
return M_PROPERTY_OK;
}
@@ -433,13 +466,12 @@ static int mp_property_time_pos(m_option_t *prop, int action,
case M_PROPERTY_SET:
if(!arg) return M_PROPERTY_ERROR;
M_PROPERTY_CLAMP(prop, *(double*)arg);
- mpctx->abs_seek_pos = SEEK_ABSOLUTE;
- mpctx->rel_seek_secs = *(double*)arg;
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double*)arg, 0);
return M_PROPERTY_OK;
case M_PROPERTY_STEP_UP:
case M_PROPERTY_STEP_DOWN:
- mpctx->rel_seek_secs += (arg ? *(double*)arg : 10.0) *
- (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0);
+ queue_seek(mpctx, MPSEEK_RELATIVE, (arg ? *(double*)arg : 10.0) *
+ (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0), 0);
return M_PROPERTY_OK;
}
return m_property_time_ro(prop, action, arg, get_current_time(mpctx));
@@ -495,20 +527,16 @@ static int mp_property_chapter(m_option_t *prop, int action, void *arg,
}
double next_pts = 0;
+ queue_seek(mpctx, MPSEEK_NONE, 0, 0);
chapter = seek_chapter(mpctx, chapter, &next_pts, &chapter_name);
- mpctx->rel_seek_secs = 0;
- mpctx->abs_seek_pos = 0;
if (chapter >= 0) {
- if (next_pts > -1.0) {
- mpctx->abs_seek_pos = SEEK_ABSOLUTE;
- mpctx->rel_seek_secs = next_pts;
- }
+ if (next_pts > -1.0)
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, next_pts, 0);
if (chapter_name)
set_osd_tmsg(OSD_MSG_TEXT, 1, opts->osd_duration,
"Chapter: (%d) %s", chapter + 1, chapter_name);
- }
- else if (step_all > 0)
- mpctx->rel_seek_secs = 1000000000.;
+ } else if (step_all > 0)
+ queue_seek(mpctx, MPSEEK_RELATIVE, 1000000000, 0);
else
set_osd_tmsg(OSD_MSG_TEXT, 1, opts->osd_duration,
"Chapter: (%d) %s", 0, mp_gtext("unknown"));
@@ -2184,6 +2212,10 @@ static const m_option_t mp_properties[] = {
M_OPT_RANGE, 0, 1, NULL },
{ "capturing", mp_property_capture, CONF_TYPE_FLAG,
M_OPT_RANGE, 0, 1, NULL },
+ { "pts_association_mode", mp_property_generic_option, &m_option_type_choice,
+ 0, 0, 0, "pts-association-mode" },
+ { "hr_seek", mp_property_generic_option, &m_option_type_choice,
+ 0, 0, 0, "hr-seek" },
// Audio
{ "volume", mp_property_volume, CONF_TYPE_FLOAT,
@@ -2357,6 +2389,8 @@ static struct property_osd_display {
{ "loop", 0, -1, _("Loop: %s") },
{ "chapter", -1, -1, NULL },
{ "capturing", 0, -1, _("Capturing: %s") },
+ { "pts_association_mode", 0, -1, "PTS association mode: %s" },
+ { "hr_seek", 0, -1, "hr-seek: %s" },
// audio
{ "volume", OSD_VOLUME, -1, _("Volume") },
{ "mute", 0, -1, _("Mute: %s") },
@@ -2679,24 +2713,19 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
if (!set_property_command(mpctx, cmd))
switch (cmd->id) {
case MP_CMD_SEEK:{
- float v;
- int abs;
mpctx->add_osd_seek_info = true;
- v = cmd->args[0].v.f;
- abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
+ float v = cmd->args[0].v.f;
+ int abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0;
+ int exact = (cmd->nargs > 2) ? cmd->args[2].v.i : 0;
if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */
- mpctx->abs_seek_pos = SEEK_ABSOLUTE;
- if (sh_video)
- mpctx->osd_function =
- (v > sh_video->pts) ? OSD_FFW : OSD_REW;
- mpctx->rel_seek_secs = v;
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, v, exact);
+ mpctx->osd_function = v > get_current_time(mpctx) ?
+ OSD_FFW : OSD_REW;
} else if (abs) { /* Absolute seek by percentage */
- mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR;
- if (sh_video)
- mpctx->osd_function = OSD_FFW; // Direction isn't set correctly
- mpctx->rel_seek_secs = v / 100.0;
+ queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, exact);
+ mpctx->osd_function = OSD_FFW; // Direction isn't set correctly
} else {
- mpctx->rel_seek_secs += v;
+ queue_seek(mpctx, MPSEEK_RELATIVE, v, exact);
mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW;
}
}
@@ -2902,12 +2931,12 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
case MP_CMD_SUB_STEP:
if (sh_video) {
int movement = cmd->args[0].v.i;
- step_sub(subdata, sh_video->pts, movement);
+ step_sub(subdata, mpctx->video_pts, movement);
#ifdef CONFIG_ASS
if (ass_track)
sub_delay +=
ass_step_sub(ass_track,
- (sh_video->pts +
+ (mpctx->video_pts +
sub_delay) * 1000 + .5, movement) / 1000.;
#endif
set_osd_tmsg(OSD_MSG_SUB_DELAY, 1, osd_duration,
diff --git a/etc/input.conf b/etc/input.conf
index 0bcfdec9f7..74373d7ffe 100644
--- a/etc/input.conf
+++ b/etc/input.conf
@@ -10,11 +10,20 @@
## If you wish to unbind a key, use key ignore.
## e.g. ENTER ignore
##
+## You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
+## modifiers Shift, Ctrl, Alt and Meta, but note that currently reading
+## key combinations is only supported through the video windows of X-based
+## output drivers (not in output windows of other drivers or in a terminal).
RIGHT seek +10
LEFT seek -10
DOWN seek -60
UP seek +60
+# Do smaller, always exact (non-keyframe-limited), seeks with shift.
+Shift+Right seek +1 0 1
+Shift+Left seek -1 0 1
+Shift+Down seek -5 0 1
+Shift+Up seek +5 0 1
PGUP seek 600
PGDWN seek -600
m mute
diff --git a/input/input.c b/input/input.c
index ab534968e3..dd4a27d63c 100644
--- a/input/input.c
+++ b/input/input.c
@@ -45,6 +45,7 @@
#include "path.h"
#include "talloc.h"
#include "options.h"
+#include "bstr.h"
#include "joystick.h"
@@ -86,7 +87,7 @@ static const mp_cmd_t mp_cmds[] = {
{ MP_CMD_RADIO_SET_FREQ, "radio_set_freq", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
{ MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
#endif
- { MP_CMD_SEEK, "seek", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
+ { MP_CMD_SEEK, "seek", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
{ MP_CMD_EDL_MARK, "edl_mark", 0, { {-1,{0}} } },
{ MP_CMD_AUDIO_DELAY, "audio_delay", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
{ MP_CMD_SPEED_INCR, "speed_incr", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
@@ -361,6 +362,16 @@ static const mp_key_name_t key_names[] = {
{ 0, NULL }
};
+struct mp_key_name modifier_names[] = {
+ { KEY_MODIFIER_SHIFT, "Shift" },
+ { KEY_MODIFIER_CTRL, "Ctrl" },
+ { KEY_MODIFIER_ALT, "Alt" },
+ { KEY_MODIFIER_META, "Meta" },
+ { 0 }
+};
+
+#define KEY_MODIFIER_MASK (KEY_MODIFIER_SHIFT | KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT | KEY_MODIFIER_META)
+
// This is the default binding. The content of input.conf overrides these.
// The first arg is a null terminated array of key codes.
// The second is the command
@@ -385,8 +396,12 @@ static const mp_cmd_bind_t def_cmd_binds[] = {
{ { KEY_RIGHT, 0 }, "seek 10" },
{ { KEY_LEFT, 0 }, "seek -10" },
+ { { KEY_MODIFIER_SHIFT + KEY_RIGHT, 0 }, "seek 1 0 1" },
+ { { KEY_MODIFIER_SHIFT + KEY_LEFT, 0 }, "seek -1 0 1" },
{ { KEY_UP, 0 }, "seek 60" },
{ { KEY_DOWN, 0 }, "seek -60" },
+ { { KEY_MODIFIER_SHIFT + KEY_UP, 0 }, "seek 5 0 1" },
+ { { KEY_MODIFIER_SHIFT + KEY_DOWN, 0 }, "seek -5 0 1" },
{ { KEY_PAGE_UP, 0 }, "seek 600" },
{ { KEY_PAGE_DOWN, 0 }, "seek -600" },
{ { '+', 0 }, "audio_delay 0.100" },
@@ -621,8 +636,27 @@ static const m_option_t mp_input_opts[] = {
static int default_cmd_func(int fd,char* buf, int l);
-static char *get_key_name(int key, char buffer[12]);
+static char *get_key_name(int key)
+{
+ char *ret = talloc_strdup(NULL, "");
+ for (int i = 0; modifier_names[i].name; i++) {
+ if (modifier_names[i].key & key) {
+ ret = talloc_asprintf_append_buffer(ret, "%s+",
+ modifier_names[i].name);
+ key -= modifier_names[i].key;
+ }
+ }
+ for (int i = 0; key_names[i].name != NULL; i++) {
+ if (key_names[i].key == key)
+ return talloc_asprintf_append_buffer(ret, "%s", key_names[i].name);
+ }
+
+ if (isascii(key))
+ return talloc_asprintf_append_buffer(ret, "%c", key);
+ // Print the hex key code
+ return talloc_asprintf_append_buffer(ret, "%#-8x", key);
+}
int mp_input_add_cmd_fd(struct input_ctx *ictx, int fd, int select,
mp_cmd_func_t read_func, mp_close_func_t close_func)
@@ -1035,7 +1069,6 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
{
char* cmd = NULL;
mp_cmd_t* ret;
- char key_buf[12];
if (ictx->cmd_binds)
cmd = find_bind_for_key(ictx->cmd_binds, n, keys);
@@ -1045,12 +1078,16 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
cmd = find_bind_for_key(def_cmd_binds,n,keys);
if(cmd == NULL) {
- mp_tmsg(MSGT_INPUT,MSGL_WARN,"No bind found for key '%s'.", get_key_name(keys[0],
- key_buf));
+ char *key_buf = get_key_name(keys[0]);
+ mp_tmsg(MSGT_INPUT,MSGL_WARN,"No bind found for key '%s'.", key_buf);
+ talloc_free(key_buf);
if(n > 1) {
int s;
- for(s=1; s < n; s++)
- mp_msg(MSGT_INPUT,MSGL_WARN,"-%s", get_key_name(keys[s], key_buf));
+ for(s=1; s < n; s++) {
+ key_buf = get_key_name(keys[s]);
+ mp_msg(MSGT_INPUT,MSGL_WARN,"-%s", key_buf);
+ talloc_free(key_buf);
+ }
}
mp_msg(MSGT_INPUT,MSGL_WARN," \n");
return NULL;
@@ -1058,13 +1095,16 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
if (strcmp(cmd, "ignore") == 0) return NULL;
ret = mp_input_parse_cmd(cmd);
if(!ret) {
- mp_tmsg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s",
- get_key_name(ictx->key_down[0], key_buf));
+ char *key_buf = get_key_name(ictx->key_down[0]);
+ mp_tmsg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s", key_buf);
+ talloc_free(key_buf);
if (ictx->num_key_down > 1) {
unsigned int s;
- for(s=1; s < ictx->num_key_down; s++)
- mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", get_key_name(ictx->key_down[s],
- key_buf));
+ for(s=1; s < ictx->num_key_down; s++) {
+ char *key_buf = get_key_name(ictx->key_down[s]);
+ mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", key_buf);
+ talloc_free(key_buf);
+ }
}
mp_msg(MSGT_INPUT,MSGL_ERR," : %s \n",cmd);
}
@@ -1077,6 +1117,14 @@ static mp_cmd_t* interpret_key(struct input_ctx *ictx, int code)
unsigned int j;
mp_cmd_t* ret;
+ /* On normal keyboards shift changes the character code of non-special
+ * keys, so don't count the modifier separately for those. In other words
+ * we want to have "a" and "A" instead of "a" and "Shift+A"; but a separate
+ * shift modifier is still kept for special keys like arrow keys.
+ */
+ if ((code & ~KEY_MODIFIER_MASK) < 256)
+ code &= ~KEY_MODIFIER_SHIFT;
+
if(mp_input_key_cb) {
if (code & MP_KEY_DOWN)
return NULL;
@@ -1372,41 +1420,34 @@ mp_cmd_clone(mp_cmd_t* cmd) {
return ret;
}
-static char *get_key_name(int key, char buffer[12])
+int mp_input_get_key_from_name(const char *name)
{
- int i;
-
- for(i = 0; key_names[i].name != NULL; i++) {
- if(key_names[i].key == key)
- return key_names[i].name;
- }
-
- if(isascii(key)) {
- snprintf(buffer, 12, "%c",(char)key);
- return buffer;
- }
-
- // Print the hex key code
- snprintf(buffer, 12, "%#-8x",key);
- return buffer;
-
-}
-
-int
-mp_input_get_key_from_name(const char *name) {
- int i,ret = 0,len = strlen(name);
- if(len == 1) { // Direct key code
- ret = (unsigned char)name[0];
- return ret;
- } else if(len > 2 && strncasecmp("0x",name,2) == 0)
- return strtol(name,NULL,16);
-
- for(i = 0; key_names[i].name != NULL; i++) {
- if(strcasecmp(key_names[i].name,name) == 0)
- return key_names[i].key;
- }
+ int modifiers = 0;
+ const char *p;
+ while (p = strchr(name, '+')) {
+ for (struct mp_key_name *m = modifier_names; m->name; m++)
+ if (!bstrcasecmp(BSTR(m->name), (struct bstr){name, p - name})) {
+ modifiers |= m->key;
+ goto found;
+ }
+ if (!strcmp(name, "+"))
+ return '+' + modifiers;
+ return -1;
+ found:
+ name = p + 1;
+ }
+ int len = strlen(name);
+ if (len == 1) // Direct key code
+ return (unsigned char)name[0] + modifiers;
+ else if (len > 2 && strncasecmp("0x", name, 2) == 0)
+ return strtol(name, NULL, 16) + modifiers;
+
+ for (int i = 0; key_names[i].name != NULL; i++) {
+ if (strcasecmp(key_names[i].name, name) == 0)
+ return key_names[i].key + modifiers;
+ }
- return -1;
+ return -1;
}
static int get_input_from_name(char* name,int* keys) {
@@ -1589,10 +1630,14 @@ static int parse_config(struct input_ctx *ictx, char *file)
// Found new line
if(iter[0] == '\n' || iter[0] == '\r') {
int i;
- char key_buf[12];
- mp_tmsg(MSGT_INPUT,MSGL_ERR,"No command found for key %s", get_key_name(keys[0], key_buf));
- for(i = 1; keys[i] != 0 ; i++)
- mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", get_key_name(keys[i], key_buf));
+ char *key_buf = get_key_name(keys[0]);
+ mp_tmsg(MSGT_INPUT,MSGL_ERR,"No command found for key %s", key_buf);
+ talloc_free(key_buf);
+ for(i = 1; keys[i] != 0 ; i++) {
+ char *key_buf = get_key_name(keys[i]);
+ mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", key_buf);
+ talloc_free(key_buf);
+ }
mp_msg(MSGT_INPUT,MSGL_ERR,"\n");
keys[0] = 0;
if(iter > buffer) {
diff --git a/libvo/video_out.c b/libvo/video_out.c
index 763527a4c1..3e2e108d4b 100644
--- a/libvo/video_out.c
+++ b/libvo/video_out.c
@@ -35,6 +35,8 @@
#include "geometry.h"
#include "old_vo_wrapper.h"
#include "input/input.h"
+#include "mp_fifo.h"
+
#include "mp_msg.h"
@@ -352,8 +354,12 @@ void vo_flip_page(struct vo *vo, unsigned int pts_us, int duration)
void vo_check_events(struct vo *vo)
{
- if (!vo->config_ok)
+ if (!vo->config_ok) {
+ if (vo->registered_fd != -1)
+ mp_input_rm_key_fd(vo->input_ctx, vo->registered_fd);
+ vo->registered_fd = -1;
return;
+ }
vo->driver->check_events(vo);
}
@@ -365,6 +371,8 @@ void vo_seek_reset(struct vo *vo)
void vo_destroy(struct vo *vo)
{
+ if (vo->registered_fd != -1)
+ mp_input_rm_key_fd(vo->input_ctx, vo->registered_fd);
vo->driver->uninit(vo);
talloc_free(vo);
}
@@ -393,6 +401,8 @@ struct vo *init_best_video_out(struct MPOpts *opts, struct vo_x11_state *x11,
.x11 = x11,
.key_fifo = key_fifo,
.input_ctx = input_ctx,
+ .event_fd = -1,
+ .registered_fd = -1,
};
// first try the preferred drivers, with their optional subdevice param:
if (vo_list && vo_list[0])
@@ -441,6 +451,13 @@ struct vo *init_best_video_out(struct MPOpts *opts, struct vo_x11_state *x11,
return NULL;
}
+static int event_fd_callback(void *ctx, int fd)
+{
+ struct vo *vo = ctx;
+ vo_check_events(vo);
+ return mplayer_get_key(vo->key_fifo, 0);
+}
+
int vo_config(struct vo *vo, uint32_t width, uint32_t height,
uint32_t d_width, uint32_t d_height, uint32_t flags,
char *title, uint32_t format)
@@ -467,6 +484,11 @@ int vo_config(struct vo *vo, uint32_t width, uint32_t height,
title, format);
vo->config_ok = (ret == 0);
vo->config_count += vo->config_ok;
+ if (vo->registered_fd == -1 && vo->event_fd != -1 && vo->config_ok) {
+ mp_input_add_key_fd(vo->input_ctx, vo->event_fd, 1, event_fd_callback,
+ NULL, vo);
+ vo->registered_fd = vo->event_fd;
+ }
return ret;
}
diff --git a/libvo/video_out.h b/libvo/video_out.h
index 39ea26a53a..36a161aaf5 100644
--- a/libvo/video_out.h
+++ b/libvo/video_out.h
@@ -251,6 +251,8 @@ struct vo {
struct vo_x11_state *x11;
struct mp_fifo *key_fifo;
struct input_ctx *input_ctx;
+ int event_fd; // check_events() should be called when this has input
+ int registered_fd; // set to event_fd when registered in input system
// requested position/resolution
int dx;
diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c
index 0dbc600847..63221782e2 100644
--- a/libvo/vo_xv.c
+++ b/libvo/vo_xv.c
@@ -61,9 +61,6 @@ Buffer allocation:
#include "subopt-helper.h"
-#include "input/input.h"
-#include "mp_fifo.h"
-
#include "libavutil/common.h"
static const vo_info_t info = {
@@ -104,7 +101,6 @@ struct xvctx {
struct vo_rect src_rect;
struct vo_rect dst_rect;
uint32_t max_width, max_height; // zero means: not set
- int event_fd_registered; // for uninit called from preinit
int mode_switched;
int osd_objects_drawn;
void (*draw_alpha_fnc)(void *ctx, int x0, int y0, int w, int h,
@@ -645,19 +641,10 @@ static void uninit(struct vo *vo)
if (ctx->mode_switched)
vo_vm_close(vo);
#endif
- if (ctx->event_fd_registered)
- mp_input_rm_key_fd(vo->input_ctx, ConnectionNumber(vo->x11->display));
// uninit() shouldn't get called unless initialization went past vo_init()
vo_x11_uninit(vo);
}
-static int x11_fd_callback(void *ctx, int fd)
-{
- struct vo *vo = ctx;
- check_events(vo);
- return mplayer_get_key(vo->key_fifo, 0);
-}
-
static int preinit(struct vo *vo, const char *arg)
{
XvPortID xv_p;
@@ -780,9 +767,6 @@ static int preinit(struct vo *vo, const char *arg)
ctx->fo = XvListImageFormats(x11->display, x11->xv_port,
(int *) &ctx->formats);
- mp_input_add_key_fd(vo->input_ctx, ConnectionNumber(x11->display), 1,
- x11_fd_callback, NULL, vo);
- ctx->event_fd_registered = 1;
return 0;
error:
diff --git a/libvo/x11_common.c b/libvo/x11_common.c
index 655b1c69d0..596645662c 100644
--- a/libvo/x11_common.c
+++ b/libvo/x11_common.c
@@ -540,12 +540,12 @@ static const struct mp_keymap keysym_map[] = {
{0, 0}
};
-static void vo_x11_putkey_ext(struct vo *vo, int keysym)
+static void vo_x11_putkey_ext(struct vo *vo, int keysym, int modifiers)
{
struct mp_fifo *f = vo->key_fifo;
int mpkey = lookup_keymap_table(keysym_map, keysym);
if (mpkey)
- mplayer_put_key(f, mpkey);
+ mplayer_put_key(f, mpkey + modifiers);
}
#endif
@@ -584,7 +584,7 @@ static const struct mp_keymap keymap[] = {
{0, 0}
};
-void vo_x11_putkey(struct vo *vo, int key)
+static void vo_x11_putkey(struct vo *vo, int key, int modifiers)
{
static const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]";
int mpkey = 0;
@@ -598,7 +598,7 @@ void vo_x11_putkey(struct vo *vo, int key)
mpkey = lookup_keymap_table(keymap, key);
if (mpkey)
- mplayer_put_key(vo->key_fifo, mpkey);
+ mplayer_put_key(vo->key_fifo, mpkey + modifiers);
}
@@ -814,13 +814,22 @@ int vo_x11_check_events(struct vo *vo)
XLookupString(&Event.xkey, buf, sizeof(buf), &keySym,
&x11->compose_status);
+ int modifiers = 0;
+ if (Event.xkey.state & ShiftMask)
+ modifiers |= KEY_MODIFIER_SHIFT;
+ if (Event.xkey.state & ControlMask)
+ modifiers |= KEY_MODIFIER_CTRL;
+ if (Event.xkey.state & Mod1Mask)
+ modifiers |= KEY_MODIFIER_ALT;
+ if (Event.xkey.state & Mod4Mask)
+ modifiers |= KEY_MODIFIER_META;
#ifdef XF86XK_AudioPause
- vo_x11_putkey_ext(vo, keySym);
+ vo_x11_putkey_ext(vo, keySym, modifiers);
#endif
key =
((keySym & 0xff00) !=
0 ? ((keySym & 0x00ff) + 256) : (keySym));
- vo_x11_putkey(vo, key);
+ vo_x11_putkey(vo, key, modifiers);
ret |= VO_EVENT_KEYPRESS;
}
break;
@@ -1123,6 +1132,7 @@ final:
x11->vo_gc = XCreateGC(mDisplay, x11->window, GCForeground, &xgcv);
XSync(mDisplay, False);
x11->vo_mouse_autohide = 1;
+ vo->event_fd = ConnectionNumber(x11->display);
}
void vo_x11_clearwindow_part(struct vo *vo, Window vo_window,
diff --git a/libvo/x11_common.h b/libvo/x11_common.h
index 57b1d79f33..824f55b4c8 100644
--- a/libvo/x11_common.h
+++ b/libvo/x11_common.h
@@ -170,8 +170,6 @@ void xv_setup_colorkeyhandling(struct vo *vo, const char *ck_method_str, const c
int xv_test_ck( void * arg );
int xv_test_ckm( void * arg );
-void vo_x11_putkey(struct vo *vo, int key);
-
#ifdef CONFIG_XF86VM
void vo_vm_switch(struct vo *vo);
void vo_vm_close(struct vo *vo);
diff --git a/m_config.c b/m_config.c
index 266ee10323..2752ced85f 100644
--- a/m_config.c
+++ b/m_config.c
@@ -150,7 +150,7 @@ static void m_option_save(const m_config_t *config, const m_option_t *opt,
void *dst)
{
if (opt->type->save) {
- const void *src = opt->new ? (char*)config->optstruct + opt->offset : opt->p;
+ const void *src = m_option_get_ptr(opt, config->optstruct);
opt->type->save(opt, dst, src);
}
}
@@ -159,7 +159,7 @@ static void m_option_set(const m_config_t *config, const m_option_t *opt,
const void *src)
{
if (opt->type->set) {
- void *dst = opt->new ? (char*)config->optstruct + opt->offset : opt->p;
+ void *dst = m_option_get_ptr(opt, config->optstruct);
opt->type->set(opt, dst, src);
}
}
diff --git a/m_option.c b/m_option.c
index 8563d21e9a..a0f01e6344 100644
--- a/m_option.c
+++ b/m_option.c
@@ -267,6 +267,50 @@ const struct m_option_type m_option_type_intpair = {
.set = copy_opt,
};
+static int parse_choice(const struct m_option *opt, const char *name,
+ const char *param, void *dst, int src)
+{
+ if (param == NULL)
+ return M_OPT_MISSING_PARAM;
+
+ struct m_opt_choice_alternatives *alt;
+ for (alt = opt->priv; alt->name; alt++)
+ if (!strcmp(param, alt->name))
+ break;
+ if (!alt->name) {
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid value for option %s: %s\n",
+ name, param);
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Valid values are:");
+ for (alt = opt->priv; alt->name; alt++)
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s", alt->name);
+ mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
+ return M_OPT_INVALID;
+ }
+ if (dst)
+ *(int *)dst = alt->value;
+
+ return 1;
+}
+
+static char *print_choice(const m_option_t *opt, const void *val)
+{
+ int v = *(int *)val;
+ struct m_opt_choice_alternatives *alt;
+ for (alt = opt->priv; alt->name; alt++)
+ if (alt->value == v)
+ return strdup(alt->name);
+ abort();
+}
+
+const struct m_option_type m_option_type_choice = {
+ .name = "String", // same as arbitrary strings in option list for now
+ .size = sizeof(int),
+ .parse = parse_choice,
+ .print = print_choice,
+ .save = copy_opt,
+ .set = copy_opt,
+};
+
// Float
#undef VAL
diff --git a/m_option.h b/m_option.h
index 26c457e24d..05d5751ceb 100644
--- a/m_option.h
+++ b/m_option.h
@@ -53,6 +53,7 @@ extern const m_option_type_t m_option_type_string_list;
extern const m_option_type_t m_option_type_position;
extern const m_option_type_t m_option_type_time;
extern const m_option_type_t m_option_type_time_size;
+extern const m_option_type_t m_option_type_choice;
extern const m_option_type_t m_option_type_print;
extern const m_option_type_t m_option_type_print_indirect;
@@ -169,6 +170,11 @@ typedef struct {
/// Ready made settings to parse a \ref m_span_t with a start-end syntax.
extern const m_obj_params_t m_span_params_def;
+struct m_opt_choice_alternatives {
+ char *name;
+ int value;
+};
+
// FIXME: backward compatibility
#define CONF_TYPE_FLAG (&m_option_type_flag)
@@ -487,6 +493,12 @@ struct m_option {
*/
const m_option_t* m_option_list_find(const m_option_t* list,const char* name);
+static inline void *m_option_get_ptr(const struct m_option *opt,
+ void *optstruct)
+{
+ return opt->new ? (char *) optstruct + opt->offset : opt->p;
+}
+
/// Helper to parse options, see \ref m_option_type::parse.
inline static int
m_option_parse(const m_option_t* opt,const char *name, const char *param, void* dst, int src) {
@@ -543,5 +555,7 @@ int parse_timestring(const char *str, double *time, char endchar);
#define OPT_STRING(optname, varname, flags) {optname, NULL, &m_option_type_string, flags, 0, 0, NULL, 1, offsetof(struct MPOpts, varname)}
#define OPT_SETTINGSLIST(optname, varname, flags, objlist) {optname, NULL, &m_option_type_obj_settings_list, flags, 0, 0, objlist, 1, offsetof(struct MPOpts, varname)}
#define OPT_AUDIOFORMAT(optname, varname, flags) {optname, NULL, &m_option_type_afmt, flags, 0, 0, NULL, 1, offsetof(struct MPOpts, varname)}
+#define OPT_HELPER_REMOVEPAREN(...) __VA_ARGS__
+#define OPT_CHOICE(optname, varname, flags, choices) {optname, NULL, &m_option_type_choice, flags, 0, 0, &(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}, 1, offsetof(struct MPOpts, varname)}
#endif /* MPLAYER_M_OPTION_H */
diff --git a/mp_core.h b/mp_core.h
index c25063368b..00b8fa91ef 100644
--- a/mp_core.h
+++ b/mp_core.h
@@ -129,6 +129,9 @@ typedef struct MPContext {
* stream by cutting samples or adding silence at the beginning to make
* audio playback position match video position. */
bool syncing_audio;
+ bool hrseek_active;
+ bool hrseek_framedrop;
+ double hrseek_pts;
// AV sync: the next frame should be shown when the audio out has this
// much (in seconds) buffered data left. Increased when more data is
// written to the ao, decreased when moving to the next frame.
@@ -148,6 +151,12 @@ typedef struct MPContext {
// the same value if the status line is updated at a time where no new
// video frame is shown.
double last_av_difference;
+ /* timestamp of video frame currently visible on screen
+ * (or at least queued to be flipped by VO) */
+ double video_pts;
+
+ // used to prevent hanging in some error cases
+ unsigned int start_timestamp;
// Timestamp from the last time some timing functions read the
// current time, in (occasionally wrapping) microseconds. Used
@@ -155,8 +164,15 @@ typedef struct MPContext {
unsigned int last_time;
// Used to communicate the parameters of a seek between parts
- double rel_seek_secs;
- int abs_seek_pos;
+ struct seek_params {
+ enum seek_type {
+ MPSEEK_NONE, MPSEEK_RELATIVE, MPSEEK_ABSOLUTE, MPSEEK_FACTOR
+ } type;
+ double amount;
+ int exact; // -1 = disable, 0 = default, 1 = enable
+ // currently not set by commands, only used internally by seek()
+ int direction; // -1 = backward, 0 = default, 1 = forward
+ } seek;
/* Heuristic for relative chapter seeks: keep track which chapter
* the user wanted to go to, even if we aren't exactly within the
@@ -218,6 +234,8 @@ int reinit_video_chain(struct MPContext *mpctx);
void pause_player(struct MPContext *mpctx);
void unpause_player(struct MPContext *mpctx);
void add_step_frame(struct MPContext *mpctx);
+void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
+ int exact);
int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts,
char **chapter_name);
double get_time_length(struct MPContext *mpctx);
diff --git a/mplayer.c b/mplayer.c
index 8056146c2b..bc12eccaf4 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1222,7 +1222,7 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
if (mpctx->sh_audio && a_pos == MP_NOPTS_VALUE)
a_pos = playing_audio_pts(mpctx);
if (mpctx->sh_audio && sh_video && at_frame) {
- mpctx->last_av_difference = a_pos - sh_video->pts - audio_delay;
+ mpctx->last_av_difference = a_pos - mpctx->video_pts - audio_delay;
if (mpctx->time_frame > 0)
mpctx->last_av_difference += mpctx->time_frame * opts->playback_speed;
if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50
@@ -1265,7 +1265,7 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
// Video time
if (sh_video)
- saddf(line, &pos, width, "V:%6.1f ", sh_video->pts);
+ saddf(line, &pos, width, "V:%6.1f ", mpctx->video_pts);
// A-V sync
if (mpctx->sh_audio && sh_video)
@@ -2080,15 +2080,28 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
return res;
int bytes;
+ bool did_retry = false;
while (1) {
double written_pts = written_audio_pts(mpctx);
- double ptsdiff = written_pts - mpctx->sh_video->pts - mpctx->delay
+ double ptsdiff = written_pts - mpctx->video_pts - mpctx->delay
- audio_delay;
bytes = ptsdiff * ao_data.bps / mpctx->opts.playback_speed;
bytes -= bytes % (ao_data.channels * af_fmt2bits(ao_data.format) / 8);
- if (fabs(ptsdiff) > 300 // pts reset or just broken?
- || written_pts <= 0) // ogg demuxers give packets without timing
+ // ogg demuxers give packets without timing
+ if (written_pts <= 1 && sh_audio->pts == MP_NOPTS_VALUE) {
+ if (!did_retry) {
+ // Try to read more data to see packets that have pts
+ int res = decode_audio(sh_audio, ao_data.bps);
+ if (res < 0)
+ return res;
+ did_retry = true;
+ continue;
+ }
+ bytes = 0;
+ }
+
+ if (fabs(ptsdiff) > 300) // pts reset or just broken?
bytes = 0;
if (bytes > 0)
@@ -2230,11 +2243,11 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
return 1;
}
-static int sleep_until_update(struct MPContext *mpctx, float *time_frame,
- float *aq_sleep_time)
+static int sleep_until_near_frame(struct MPContext *mpctx, float *time_frame,
+ float *aq_sleep_time)
{
struct MPOpts *opts = &mpctx->opts;
- int frame_time_remaining = 0;
+ double audio_limit = 2;
current_module="calc_sleep_time";
*time_frame -= get_relative_time(mpctx); // reset timer
@@ -2259,17 +2272,11 @@ static int sleep_until_update(struct MPContext *mpctx, float *time_frame,
}
*time_frame = delay - mpctx->delay / opts->playback_speed;
- *time_frame -= mpctx->video_out->flip_queue_offset;
// delay = amount of audio buffered in soundcard/driver
- if (delay > 0.25) delay=0.25; else
- if (delay < 0.10) delay=0.10;
-
- if (*time_frame > delay*0.6) {
- // sleep time too big - may cause audio drops (buffer underrun)
- frame_time_remaining = 1;
- *time_frame = delay*0.5;
- }
+ delay = FFMIN(delay, 0.5);
+ delay = FFMAX(delay, 0.1);
+ audio_limit = delay;
} else {
// If we're lagging more than 200 ms behind the right playback rate,
// don't try to "catch up".
@@ -2277,19 +2284,19 @@ static int sleep_until_update(struct MPContext *mpctx, float *time_frame,
// without sleeping.
if (*time_frame < -0.2 || opts->benchmark)
*time_frame = 0;
- *time_frame -= mpctx->video_out->flip_queue_offset;
}
- *aq_sleep_time += *time_frame;
+ double t = *time_frame - mpctx->video_out->flip_queue_offset;
+ if (t <= 0.05)
+ return 0;
- //============================== SLEEP: ===================================
-
- // flag 256 means: libvo driver does its timing (dvb card)
- if (*time_frame > 0.001 && !(mpctx->sh_video->output_flags&256))
- *time_frame = timing_sleep(mpctx, *time_frame);
- *time_frame += mpctx->video_out->flip_queue_offset;
- return frame_time_remaining;
+ t -= 0.05;
+ if (t > audio_limit * 0.6)
+ t = audio_limit * 0.5;
+ *aq_sleep_time += t;
+ mp_input_get_cmd(mpctx->input, t * 1000 + 1, 1);
+ return 1;
}
int reinit_video_chain(struct MPContext *mpctx)
@@ -2413,13 +2420,13 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx)
struct sh_video *sh_video = mpctx->sh_video;
double frame_time = 0;
struct vo *video_out = mpctx->video_out;
- while (!video_out->frame_loaded) {
+ while (1) {
current_module = "filter_video";
// In nocorrect-pts mode there is no way to properly time these frames
if (vo_get_buffered_frame(video_out, 0) >= 0)
break;
if (vf_output_queued_frame(sh_video->vfilter))
- continue;
+ break;
unsigned char *packet = NULL;
frame_time = sh_video->next_frame_time;
if (mpctx->restart_playback)
@@ -2463,10 +2470,9 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx)
#endif
if (decoded_frame) {
current_module = "filter video";
- if (filter_video(sh_video, decoded_frame, sh_video->pts))
- if (!video_out->config_ok)
- break;
+ filter_video(sh_video, decoded_frame, sh_video->pts);
}
+ break;
}
return frame_time;
}
@@ -2513,21 +2519,20 @@ static double update_video(struct MPContext *mpctx)
double pts;
- bool hit_eof = false;
- while (!video_out->frame_loaded) {
+ while (1) {
current_module = "filter_video";
- if (vo_get_buffered_frame(video_out, hit_eof) >= 0)
+ if (!mpctx->hrseek_active
+ && vo_get_buffered_frame(video_out, false) >= 0)
break;
// XXX Time used in this call is not counted in any performance
- // timer now, OSD time is not updated correctly for filter-added frames
+ // timer now
if (vf_output_queued_frame(sh_video->vfilter))
- continue;
- if (hit_eof)
- return -1;
+ break;
unsigned char *packet = NULL;
int in_size = ds_get_packet_pts(mpctx->d_video, &packet, &pts);
if (pts != MP_NOPTS_VALUE)
pts += mpctx->video_offset;
+ bool hit_eof = false;
if (in_size < 0) {
// try to extract last frames in case of decoder lag
in_size = 0;
@@ -2537,18 +2542,26 @@ static double update_video(struct MPContext *mpctx)
if (in_size > max_framesize)
max_framesize = in_size;
current_module = "decode video";
- int framedrop_type = check_framedrop(mpctx, sh_video->frametime);
+ if (pts >= mpctx->hrseek_pts - .005)
+ mpctx->hrseek_framedrop = false;
+ int framedrop_type = mpctx->hrseek_framedrop ? 1 :
+ check_framedrop(mpctx, sh_video->frametime);
void *decoded_frame = decode_video(sh_video, packet, in_size,
framedrop_type, pts);
if (decoded_frame) {
determine_frame_pts(mpctx);
current_module = "filter video";
- if (filter_video(sh_video, decoded_frame, sh_video->pts))
- if (!video_out->config_ok)
- break; // We'd likely hang in this loop otherwise
+ filter_video(sh_video, decoded_frame, sh_video->pts);
+ } else if (hit_eof) {
+ if (vo_get_buffered_frame(video_out, true) < 0)
+ return -1;
}
+ break;
}
+ if (!video_out->frame_loaded)
+ return 0;
+
pts = video_out->next_pts;
if (pts == MP_NOPTS_VALUE) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, "Video pts after filters MISSING\n");
@@ -2557,6 +2570,9 @@ static double update_video(struct MPContext *mpctx)
if (pts == MP_NOPTS_VALUE)
pts = sh_video->last_pts;
}
+ if (mpctx->hrseek_active && pts < mpctx->hrseek_pts - .005)
+ return 0;
+ mpctx->hrseek_active = false;
sh_video->pts = pts;
if (sh_video->last_pts == MP_NOPTS_VALUE)
sh_video->last_pts = sh_video->pts;
@@ -2668,7 +2684,7 @@ static void edl_seek_reset(MPContext *mpctx)
next_edl_record = edl_records;
while (next_edl_record) {
- if (next_edl_record->start_sec >= mpctx->sh_video->pts)
+ if (next_edl_record->start_sec >= get_current_time(mpctx))
break;
if (next_edl_record->action == EDL_MUTE)
@@ -2694,11 +2710,10 @@ static void edl_update(MPContext *mpctx)
return;
}
- if (mpctx->sh_video->pts >= next_edl_record->start_sec) {
+ if (get_current_time(mpctx) >= next_edl_record->start_sec) {
if (next_edl_record->action == EDL_SKIP) {
mpctx->osd_function = OSD_FFW;
- mpctx->abs_seek_pos = 0;
- mpctx->rel_seek_secs = next_edl_record->length_sec;
+ queue_seek(mpctx, MPSEEK_RELATIVE, next_edl_record->length_sec, 0);
mp_msg(MSGT_CPLAYER, MSGL_DBG4, "EDL_SKIP: start [%f], stop "
"[%f], length [%f]\n", next_edl_record->start_sec,
next_edl_record->stop_sec, next_edl_record->length_sec);
@@ -2738,6 +2753,7 @@ static void seek_reset(struct MPContext *mpctx)
// (which is used by at least vobsub and edl code below) may
// be completely wrong (probably 0).
mpctx->sh_video->pts = mpctx->d_video->pts + mpctx->video_offset;
+ mpctx->video_pts = mpctx->sh_video->pts;
update_subtitles(mpctx, &mpctx->opts, mpctx->sh_video,
mpctx->sh_video->pts, mpctx->video_offset,
mpctx->d_sub, 1);
@@ -2762,6 +2778,8 @@ static void seek_reset(struct MPContext *mpctx)
edl_seek_reset(mpctx);
+ mpctx->hrseek_active = false;
+ mpctx->hrseek_framedrop = false;
mpctx->total_avsync_change = 0;
audio_time_usage = 0; video_time_usage = 0; vout_time_usage = 0;
drop_frame_cnt = 0;
@@ -2805,39 +2823,43 @@ static double timeline_set_from_time(struct MPContext *mpctx, double pts,
}
-// style & SEEK_ABSOLUTE == 0 means seek relative to current position, == 1 means absolute
-// style & SEEK_FACTOR == 0 means amount in seconds, == 2 means fraction of file length
// return -1 if seek failed (non-seekable stream?), 0 otherwise
-static int seek(MPContext *mpctx, double amount, int style)
+static int seek(MPContext *mpctx, struct seek_params seek)
{
+ struct MPOpts *opts = &mpctx->opts;
+
current_module = "seek";
if (mpctx->stop_play == AT_END_OF_FILE)
mpctx->stop_play = KEEP_PLAYING;
- if (style & SEEK_FACTOR
- || style & SEEK_ABSOLUTE && amount < mpctx->last_chapter_pts
- || amount < 0)
+ bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts;
+ hr_seek &= seek.exact >= 0 && seek.type != MPSEEK_FACTOR;
+ hr_seek &= opts->hr_seek == 0 && seek.type == MPSEEK_ABSOLUTE
+ || opts->hr_seek > 0 || seek.exact > 0;
+ if (seek.type == MPSEEK_FACTOR
+ || seek.type == MPSEEK_ABSOLUTE
+ && seek.amount < mpctx->last_chapter_pts
+ || seek.amount < 0)
mpctx->last_chapter_seek = -1;
- if (mpctx->timeline && style & SEEK_FACTOR) {
- amount *= mpctx->timeline[mpctx->num_timeline_parts].start;
- style &= ~SEEK_FACTOR;
+ if (mpctx->timeline && seek.type == MPSEEK_FACTOR) {
+ seek.amount *= mpctx->timeline[mpctx->num_timeline_parts].start;
+ seek.type = MPSEEK_ABSOLUTE;
}
- if ((mpctx->demuxer->accurate_seek || mpctx->timeline) && mpctx->sh_video
- && !(style & (SEEK_ABSOLUTE | SEEK_FACTOR))) {
- style |= SEEK_ABSOLUTE;
- if (amount > 0)
- style |= SEEK_FORWARD;
- else
- style |= SEEK_BACKWARD;
- amount += mpctx->sh_video->pts;
+ if ((mpctx->demuxer->accurate_seek || mpctx->timeline)
+ && seek.type == MPSEEK_RELATIVE) {
+ seek.type = MPSEEK_ABSOLUTE;
+ seek.direction = seek.amount > 0 ? 1 : -1;
+ seek.amount += get_current_time(mpctx);
}
/* At least the liba52 decoder wants to read from the input stream
* during initialization, so reinit must be done after the demux_seek()
* call that clears possible stream EOF. */
bool need_reset = false;
+ double demuxer_amount = seek.amount;
if (mpctx->timeline) {
- amount = timeline_set_from_time(mpctx, amount, &need_reset);
- if (amount == -1) {
+ demuxer_amount = timeline_set_from_time(mpctx, seek.amount,
+ &need_reset);
+ if (demuxer_amount == -1) {
mpctx->stop_play = AT_END_OF_FILE;
// Clear audio from current position
if (mpctx->sh_audio) {
@@ -2848,16 +2870,78 @@ static int seek(MPContext *mpctx, double amount, int style)
return -1;
}
}
- int seekresult = demux_seek(mpctx->demuxer, amount, audio_delay, style);
+ int demuxer_style = 0;
+ switch (seek.type) {
+ case MPSEEK_FACTOR:
+ demuxer_style |= SEEK_FACTOR; // fallthrough
+ case MPSEEK_ABSOLUTE:
+ demuxer_style |= SEEK_ABSOLUTE;
+ }
+ if (hr_seek || seek.direction < 0)
+ demuxer_style |= SEEK_BACKWARD;
+ else if (seek.direction > 0)
+ demuxer_style |= SEEK_FORWARD;
+
+ int seekresult = demux_seek(mpctx->demuxer, demuxer_amount, audio_delay,
+ demuxer_style);
if (need_reset)
reinit_decoders(mpctx);
if (seekresult == 0)
return -1;
seek_reset(mpctx);
+
+ /* Use the target time as "current position" for further relative
+ * seeks etc until a new video frame has been decoded */
+ if (seek.type == MPSEEK_ABSOLUTE)
+ mpctx->video_pts = seek.amount;
+
+ if (hr_seek) {
+ mpctx->hrseek_active = true;
+ mpctx->hrseek_framedrop = true;
+ mpctx->hrseek_pts = seek.amount;
+ }
+
+ mpctx->start_timestamp = GetTimerMS();
+
return 0;
}
+void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
+ int exact)
+{
+ struct seek_params *seek = &mpctx->seek;
+ switch (type) {
+ case MPSEEK_RELATIVE:
+ if (seek->type == MPSEEK_FACTOR)
+ return; // Well... not common enough to bother doing better
+ seek->amount += amount;
+ seek->exact = FFMAX(seek->exact, exact);
+ if (seek->type == MPSEEK_NONE)
+ seek->exact = exact;
+ if (seek->type == MPSEEK_ABSOLUTE)
+ return;
+ if (seek->amount == 0) {
+ *seek = (struct seek_params){0};
+ return;
+ }
+ seek->type = MPSEEK_RELATIVE;
+ return;
+ case MPSEEK_ABSOLUTE:
+ case MPSEEK_FACTOR:
+ *seek = (struct seek_params) {
+ .type = type,
+ .amount = amount,
+ .exact = exact,
+ };
+ return;
+ case MPSEEK_NONE:
+ *seek = (struct seek_params){0};
+ return;
+ }
+ abort();
+}
+
double get_time_length(struct MPContext *mpctx)
{
@@ -2895,7 +2979,7 @@ double get_current_time(struct MPContext *mpctx)
return demuxer->stream_pts;
struct sh_video *sh_video = demuxer->video->sh;
if (sh_video)
- return sh_video->pts;
+ return mpctx->video_pts;
return playing_audio_pts(mpctx);
}
@@ -2977,6 +3061,302 @@ int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts,
return chapter;
}
+
+static void run_playloop(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
+ float aq_sleep_time = 0;
+
+ if (opts->chapterrange[1] > 0) {
+ int cur_chapter = get_current_chapter(mpctx);
+ if (cur_chapter!=-1 && cur_chapter + 1 > opts->chapterrange[1])
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ }
+
+ if (!mpctx->sh_audio && mpctx->d_audio->sh) {
+ mpctx->sh_audio = mpctx->d_audio->sh;
+ mpctx->sh_audio->ds = mpctx->d_audio;
+ reinit_audio_chain(mpctx);
+ }
+
+/*========================== PLAY AUDIO ============================*/
+
+ if (mpctx->sh_audio && !mpctx->paused
+ && (!mpctx->restart_playback || !mpctx->sh_video))
+ if (!fill_audio_out_buffers(mpctx))
+ // at eof, all audio at least written to ao
+ if (!mpctx->sh_video)
+ mpctx->stop_play = AT_END_OF_FILE;
+
+
+ if (!mpctx->sh_video) {
+ mpctx->restart_playback = false;
+ // handle audio-only case:
+ double a_pos = 0;
+ // sh_audio can be NULL due to video stream switching
+ // TODO: handle this better
+ if (mpctx->sh_audio)
+ a_pos = playing_audio_pts(mpctx);
+
+ print_status(mpctx, a_pos, false);
+
+ if (end_at.type == END_AT_TIME && end_at.pos < a_pos)
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ update_subtitles(mpctx, &mpctx->opts, NULL, a_pos, mpctx->video_offset,
+ mpctx->d_sub, 0);
+ update_osd_msg(mpctx);
+ } else {
+
+/*========================== PLAY VIDEO ============================*/
+
+ vo_pts = mpctx->sh_video->timer * 90000.0;
+ vo_fps = mpctx->sh_video->fps;
+
+ bool blit_frame = mpctx->video_out->frame_loaded;
+ if (!blit_frame || mpctx->hrseek_active) {
+ double frame_time = update_video(mpctx);
+ blit_frame = mpctx->video_out->frame_loaded;
+ blit_frame &= !mpctx->hrseek_active;
+ mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "*** ftime=%5.3f ***\n", frame_time);
+ if (mpctx->sh_video->vf_initialized < 0) {
+ mp_tmsg(MSGT_CPLAYER, MSGL_FATAL,
+ "\nFATAL: Could not initialize video filters (-vf) "
+ "or video output (-vo).\n");
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ return;
+ }
+ if (frame_time < 0)
+ mpctx->stop_play = AT_END_OF_FILE;
+ else if (!mpctx->restart_playback) {
+ mpctx->time_frame += frame_time / opts->playback_speed;
+ adjust_sync(mpctx, frame_time);
+ }
+ }
+ if (mpctx->timeline) {
+ struct timeline_part *next =
+ mpctx->timeline + mpctx->timeline_part + 1;
+ if (mpctx->sh_video->pts >= next->start
+ || mpctx->stop_play == AT_END_OF_FILE
+ && mpctx->timeline_part + 1 < mpctx->num_timeline_parts) {
+ seek(mpctx, (struct seek_params){ .type = MPSEEK_ABSOLUTE,
+ .amount = next->start });
+ return;
+ }
+ }
+
+// ==========================================================================
+
+ current_module = "vo_check_events";
+ vo_check_events(mpctx->video_out);
+
+#ifdef CONFIG_X11
+ if (stop_xscreensaver) {
+ current_module = "stop_xscreensaver";
+ xscreensaver_heartbeat(mpctx->x11_state);
+ }
+#endif
+ if (heartbeat_cmd) {
+ static unsigned last_heartbeat;
+ unsigned now = GetTimerMS();
+ if (now - last_heartbeat > 30000) {
+ last_heartbeat = now;
+ system(heartbeat_cmd);
+ }
+ }
+
+ bool frame_time_remaining = sleep_until_near_frame(mpctx,
+ &mpctx->time_frame,
+ &aq_sleep_time);
+
+//====================== FLIP PAGE (VIDEO BLT): =========================
+
+ current_module = "flip_page";
+ if (!frame_time_remaining && blit_frame) {
+ struct sh_video *sh_video = mpctx->sh_video;
+ mpctx->video_pts = sh_video->pts;
+ update_subtitles(mpctx, &mpctx->opts, sh_video, sh_video->pts,
+ mpctx->video_offset, mpctx->d_sub, 0);
+ update_teletext(sh_video, mpctx->demuxer, 0);
+ update_osd_msg(mpctx);
+ struct vf_instance *vf = sh_video->vfilter;
+ vf->control(vf, VFCTRL_DRAW_EOSD, NULL);
+ vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd);
+ vo_osd_changed(0);
+
+ mpctx->time_frame -= mpctx->video_out->flip_queue_offset;
+ aq_sleep_time += mpctx->time_frame;
+ // flag 256 means: libvo driver does its timing (dvb card)
+ if (mpctx->time_frame > 0.001
+ && !(mpctx->sh_video->output_flags&256))
+ mpctx->time_frame = timing_sleep(mpctx, mpctx->time_frame);
+ mpctx->time_frame += mpctx->video_out->flip_queue_offset;
+
+ unsigned int t2 = GetTimer();
+ unsigned int pts_us = mpctx->last_time + mpctx->time_frame * 1e6;
+ int duration = -1;
+ double pts2 = mpctx->video_out->next_pts2;
+ if (pts2 != MP_NOPTS_VALUE && opts->correct_pts
+ && !mpctx->restart_playback) {
+ // expected A/V sync correction is ignored
+ double diff = (pts2 - mpctx->video_pts);
+ diff /= opts->playback_speed;
+ if (mpctx->time_frame < 0)
+ diff += mpctx->time_frame;
+ if (diff < 0)
+ diff = 0;
+ if (diff > 10)
+ diff = 10;
+ duration = diff * 1e6;
+ }
+ vo_flip_page(mpctx->video_out, pts_us | 1, duration);
+
+ mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001;
+ vout_time_usage += mpctx->last_vo_flip_duration;
+ if (mpctx->video_out->driver->flip_page_timed) {
+ // No need to adjust sync based on flip speed
+ mpctx->last_vo_flip_duration = 0;
+ // For print_status - VO call finishing early is OK for sync
+ mpctx->time_frame -= get_relative_time(mpctx);
+ }
+ if (mpctx->restart_playback) {
+ mpctx->syncing_audio = true;
+ if (mpctx->sh_audio && !mpctx->paused)
+ fill_audio_out_buffers(mpctx);
+ mpctx->restart_playback = false;
+ mpctx->time_frame = 0;
+ get_relative_time(mpctx);
+ }
+ print_status(mpctx, MP_NOPTS_VALUE, true);
+ } else
+ print_status(mpctx, MP_NOPTS_VALUE, false);
+
+//============================ Auto QUALITY ============================
+
+/*Output quality adjustments:*/
+ if (opts->auto_quality > 0) {
+ current_module = "autoq";
+ if (output_quality < opts->auto_quality && aq_sleep_time > 0)
+ ++output_quality;
+ else
+ if (output_quality>1 && aq_sleep_time<0)
+ --output_quality;
+ else if (output_quality>0 && aq_sleep_time<-0.050f) // 50ms
+ output_quality = 0;
+ set_video_quality(mpctx->sh_video, output_quality);
+ }
+
+ if (!frame_time_remaining && blit_frame) {
+ if (play_n_frames >= 0) {
+ --play_n_frames;
+ if (play_n_frames <= 0)
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ }
+ if (mpctx->step_frames > 0) {
+ mpctx->step_frames--;
+ if (mpctx->step_frames == 0)
+ pause_player(mpctx);
+ }
+ }
+
+// FIXME: add size based support for -endpos
+ if (end_at.type == END_AT_TIME &&
+ !frame_time_remaining && end_at.pos <= mpctx->sh_video->pts)
+ mpctx->stop_play = PT_NEXT_ENTRY;
+
+ } // end if(mpctx->sh_video)
+
+#ifdef CONFIG_DVDNAV
+ if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
+ nav_highlight_t hl;
+ mp_dvdnav_get_highlight(mpctx->stream, &hl);
+ if (!vo_spudec || !spudec_apply_palette_crop(vo_spudec, hl.palette, hl.sx, hl.sy, hl.ex, hl.ey)) {
+ osd_set_nav_box(hl.sx, hl.sy, hl.ex, hl.ey);
+ vo_osd_changed(OSDTYPE_DVDNAV);
+ } else {
+ osd_set_nav_box(0, 0, 0, 0);
+ vo_osd_changed(OSDTYPE_DVDNAV);
+ vo_osd_changed(OSDTYPE_SPU);
+ }
+
+ if (mp_dvdnav_stream_has_changed(mpctx->stream)) {
+ double ar = -1.0;
+ if (mpctx->sh_video &&
+ stream_control(mpctx->demuxer->stream,
+ STREAM_CTRL_GET_ASPECT_RATIO, &ar)
+ != STREAM_UNSUPPORTED)
+ mpctx->sh_video->stream_aspect = ar;
+ }
+ }
+#endif
+
+//================= Keyboard events, SEEKing ====================
+
+ current_module = "key_events";
+
+ while (1) {
+ mp_cmd_t *cmd;
+ while ((cmd = mp_input_get_cmd(mpctx->input, 0, 1)) != NULL) {
+ /* Allow running consecutive seek commands to combine them,
+ * but execute the seek before running other commands.
+ * If the user seeks continuously (keeps arrow key down)
+ * try to finish showing a frame from one location before doing
+ * another seek (which could lead to unchanging display). */
+ if (mpctx->seek.type && cmd->id != MP_CMD_SEEK
+ || mpctx->restart_playback && cmd->id == MP_CMD_SEEK
+ && GetTimerMS() - mpctx->start_timestamp < 300)
+ break;
+ cmd = mp_input_get_cmd(mpctx->input, 0, 0);
+ run_command(mpctx, cmd);
+ mp_cmd_free(cmd);
+ if (mpctx->stop_play)
+ break;
+ }
+ if (!mpctx->paused || mpctx->stop_play || mpctx->seek.type
+ || mpctx->restart_playback)
+ break;
+ if (mpctx->sh_video) {
+ update_osd_msg(mpctx);
+ int hack = vo_osd_changed(0);
+ vo_osd_changed(hack);
+ if (hack) {
+ if (redraw_osd(mpctx->sh_video, mpctx->osd) < 0) {
+ add_step_frame(mpctx);
+ break;
+ } else
+ vo_osd_changed(0);
+ }
+ }
+ pause_loop(mpctx);
+ }
+
+// handle -sstep
+ if (step_sec > 0 && !mpctx->paused) {
+ mpctx->osd_function = OSD_FFW;
+ queue_seek(mpctx, MPSEEK_RELATIVE, step_sec, 0);
+ }
+
+ edl_update(mpctx);
+
+ /* Looping. */
+ if (mpctx->stop_play==AT_END_OF_FILE && opts->loop_times>=0) {
+ mp_msg(MSGT_CPLAYER, MSGL_V, "loop_times = %d\n", opts->loop_times);
+
+ if (opts->loop_times>1)
+ opts->loop_times--;
+ else if (opts->loop_times==1)
+ opts->loop_times = -1;
+ play_n_frames = play_n_frames_mf;
+ mpctx->stop_play = 0;
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, 0, 0);
+ }
+
+ if (mpctx->seek.type) {
+ seek(mpctx, mpctx->seek);
+ mpctx->seek = (struct seek_params){0};
+ }
+}
+
+
static int find_ordered_chapter_sources(struct MPContext *mpctx,
struct content_source *sources,
int num_sources,
@@ -4072,8 +4452,6 @@ if (verbose)
opts->term_osd = 0;
{
-int frame_time_remaining=0; // flag
-int blit_frame=0;
// Make sure old OSD does not stay around,
// e.g. with -fixed-vo and same-resolution files
@@ -4149,16 +4527,28 @@ if(play_n_frames==0){
mpctx->stop_play=PT_NEXT_ENTRY; goto goto_next_file;
}
+ mpctx->time_frame = 0;
+ mpctx->drop_message_shown = 0;
+ mpctx->restart_playback = true;
+ mpctx->video_pts = 0;
+ mpctx->hrseek_active = false;
+ mpctx->hrseek_framedrop = false;
+ mpctx->total_avsync_change = 0;
+ mpctx->last_chapter_seek = -1;
+
// If there's a timeline force an absolute seek to initialize state
if (seek_to_sec || mpctx->timeline) {
- seek(mpctx, seek_to_sec, SEEK_ABSOLUTE);
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_to_sec, 0);
+ seek(mpctx, mpctx->seek);
end_at.pos += seek_to_sec;
}
if (opts->chapterrange[0] > 0) {
double pts;
if (seek_chapter(mpctx, opts->chapterrange[0]-1, &pts, NULL) >= 0
- && pts > -1.0)
- seek(mpctx, pts, SEEK_ABSOLUTE);
+ && pts > -1.0) {
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, pts, 0);
+ seek(mpctx, mpctx->seek);
+ }
}
if (end_at.type == END_AT_SIZE) {
@@ -4174,304 +4564,15 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
}
#endif
+ mpctx->seek = (struct seek_params){0};
get_relative_time(mpctx); // reset current delta
- mpctx->time_frame = 0;
- mpctx->drop_message_shown = 0;
- mpctx->restart_playback = true;
- mpctx->total_avsync_change = 0;
- mpctx->last_chapter_seek = -1;
// Make sure VO knows current pause state
if (mpctx->sh_video)
vo_control(mpctx->video_out, mpctx->paused ? VOCTRL_PAUSE : VOCTRL_RESUME,
NULL);
-while(!mpctx->stop_play){
- float aq_sleep_time=0;
-
-if (opts->chapterrange[1] > 0) {
- int cur_chapter = get_current_chapter(mpctx);
- if(cur_chapter!=-1 && cur_chapter+1 > opts->chapterrange[1])
- goto goto_next_file;
-}
-
-if(!mpctx->sh_audio && mpctx->d_audio->sh) {
- mpctx->sh_audio = mpctx->d_audio->sh;
- mpctx->sh_audio->ds = mpctx->d_audio;
- reinit_audio_chain(mpctx);
-}
-
-/*========================== PLAY AUDIO ============================*/
-
-if (mpctx->sh_audio && !mpctx->paused
- && (!mpctx->restart_playback || !mpctx->sh_video))
- if (!fill_audio_out_buffers(mpctx))
- // at eof, all audio at least written to ao
- if (!mpctx->sh_video)
- mpctx->stop_play = AT_END_OF_FILE;
-
-
-if(!mpctx->sh_video) {
- // handle audio-only case:
- double a_pos=0;
- // sh_audio can be NULL due to video stream switching
- // TODO: handle this better
- if (mpctx->sh_audio)
- a_pos = playing_audio_pts(mpctx);
-
- print_status(mpctx, a_pos, false);
-
- if(end_at.type == END_AT_TIME && end_at.pos < a_pos)
- mpctx->stop_play = PT_NEXT_ENTRY;
- update_subtitles(mpctx, &mpctx->opts, NULL, a_pos, mpctx->video_offset,
- mpctx->d_sub, 0);
- update_osd_msg(mpctx);
-
-} else {
-
-/*========================== PLAY VIDEO ============================*/
-
- vo_pts=mpctx->sh_video->timer*90000.0;
- vo_fps=mpctx->sh_video->fps;
-
- blit_frame = mpctx->video_out->frame_loaded;
- if (!blit_frame) {
- double frame_time = update_video(mpctx);
- blit_frame = mpctx->video_out->frame_loaded;
- mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"*** ftime=%5.3f ***\n",frame_time);
- if (mpctx->sh_video->vf_initialized < 0) {
- mp_tmsg(MSGT_CPLAYER,MSGL_FATAL, "\nFATAL: Could not initialize video filters (-vf) or video output (-vo).\n");
- mpctx->stop_play = PT_NEXT_ENTRY;
- goto goto_next_file;
- }
- if (blit_frame) {
- struct sh_video *sh_video = mpctx->sh_video;
- update_subtitles(mpctx, &mpctx->opts, sh_video, sh_video->pts,
- mpctx->video_offset, mpctx->d_sub, 0);
- update_teletext(sh_video, mpctx->demuxer, 0);
- update_osd_msg(mpctx);
- struct vf_instance *vf = mpctx->sh_video->vfilter;
- vf->control(vf, VFCTRL_DRAW_EOSD, NULL);
- vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd);
- vo_osd_changed(0);
- }
- if (frame_time < 0)
- mpctx->stop_play = AT_END_OF_FILE;
- else if (!mpctx->restart_playback) {
- mpctx->time_frame += frame_time / opts->playback_speed;
- adjust_sync(mpctx, frame_time);
- }
- }
- if (mpctx->timeline) {
- struct timeline_part *next = mpctx->timeline + mpctx->timeline_part + 1;
- if (mpctx->sh_video->pts >= next->start
- || mpctx->stop_play == AT_END_OF_FILE
- && mpctx->timeline_part + 1 < mpctx->num_timeline_parts) {
- seek(mpctx, next->start, SEEK_ABSOLUTE);
- continue;
- }
- }
-
-// ==========================================================================
-
-// current_module="draw_osd";
-// if(vo_config_count) mpctx->video_out->draw_osd();
-
- current_module="vo_check_events";
- vo_check_events(mpctx->video_out);
-
-#ifdef CONFIG_X11
- if (stop_xscreensaver) {
- current_module = "stop_xscreensaver";
- xscreensaver_heartbeat(mpctx->x11_state);
- }
-#endif
- if (heartbeat_cmd) {
- static unsigned last_heartbeat;
- unsigned now = GetTimerMS();
- if (now - last_heartbeat > 30000) {
- last_heartbeat = now;
- system(heartbeat_cmd);
- }
- }
-
- frame_time_remaining = sleep_until_update(mpctx, &mpctx->time_frame, &aq_sleep_time);
-
-//====================== FLIP PAGE (VIDEO BLT): =========================
-
- current_module="flip_page";
- if (!frame_time_remaining && blit_frame) {
- unsigned int t2=GetTimer();
- unsigned int pts_us = mpctx->last_time + mpctx->time_frame * 1e6;
- int duration = -1;
- double pts2 = mpctx->video_out->next_pts2;
- if (pts2 != MP_NOPTS_VALUE && opts->correct_pts
- && !mpctx->restart_playback) {
- // expected A/V sync correction is ignored
- double diff = (pts2 - mpctx->sh_video->pts);
- diff /= opts->playback_speed;
- if (mpctx->time_frame < 0)
- diff += mpctx->time_frame;
- if (diff < 0)
- diff = 0;
- if (diff > 10)
- diff = 10;
- duration = diff * 1e6;
- }
- vo_flip_page(mpctx->video_out, pts_us|1, duration);
-
- mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001;
- vout_time_usage += mpctx->last_vo_flip_duration;
- if (mpctx->video_out->driver->flip_page_timed) {
- // No need to adjust sync based on flip speed
- mpctx->last_vo_flip_duration = 0;
- // For print_status - VO call finishing early is OK for sync
- mpctx->time_frame -= get_relative_time(mpctx);
- }
- if (mpctx->restart_playback) {
- mpctx->syncing_audio = true;
- if (mpctx->sh_audio && !mpctx->paused)
- fill_audio_out_buffers(mpctx);
- mpctx->restart_playback = false;
- mpctx->time_frame = 0;
- get_relative_time(mpctx);
- }
- print_status(mpctx, MP_NOPTS_VALUE, true);
- }
- else
- print_status(mpctx, MP_NOPTS_VALUE, false);
-
-//============================ Auto QUALITY ============================
-
-/*Output quality adjustments:*/
-if (opts->auto_quality > 0) {
- current_module="autoq";
-// float total=0.000001f * (GetTimer()-aq_total_time);
-// if (output_quality < opts->auto_quality && aq_sleep_time > 0.05f * total)
- if (output_quality < opts->auto_quality && aq_sleep_time > 0)
- ++output_quality;
- else
-// if(output_quality>0 && aq_sleep_time<-0.05f*total)
- if(output_quality>1 && aq_sleep_time<0)
- --output_quality;
- else
- if(output_quality>0 && aq_sleep_time<-0.050f) // 50ms
- output_quality=0;
-// printf("total: %8.6f sleep: %8.6f q: %d\n",(0.000001f*aq_total_time),aq_sleep_time,output_quality);
- set_video_quality(mpctx->sh_video,output_quality);
-}
-
- if (!frame_time_remaining && blit_frame) {
- if (play_n_frames >= 0) {
- --play_n_frames;
- if (play_n_frames <= 0)
- mpctx->stop_play = PT_NEXT_ENTRY;
- }
- if (mpctx->step_frames > 0) {
- mpctx->step_frames--;
- if (mpctx->step_frames == 0)
- pause_player(mpctx);
- }
- }
-
-
-// FIXME: add size based support for -endpos
- if (end_at.type == END_AT_TIME &&
- !frame_time_remaining && end_at.pos <= mpctx->sh_video->pts)
- mpctx->stop_play = PT_NEXT_ENTRY;
-
-} // end if(mpctx->sh_video)
-
-#ifdef CONFIG_DVDNAV
- if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
- nav_highlight_t hl;
- mp_dvdnav_get_highlight (mpctx->stream, &hl);
- if (!vo_spudec || !spudec_apply_palette_crop(vo_spudec, hl.palette, hl.sx, hl.sy, hl.ex, hl.ey)) {
- osd_set_nav_box (hl.sx, hl.sy, hl.ex, hl.ey);
- vo_osd_changed (OSDTYPE_DVDNAV);
- } else {
- osd_set_nav_box(0, 0, 0, 0);
- vo_osd_changed(OSDTYPE_DVDNAV);
- vo_osd_changed(OSDTYPE_SPU);
- }
-
- if (mp_dvdnav_stream_has_changed(mpctx->stream)) {
- double ar = -1.0;
- if (mpctx->sh_video &&
- stream_control (mpctx->demuxer->stream,
- STREAM_CTRL_GET_ASPECT_RATIO, &ar)
- != STREAM_UNSUPPORTED)
- mpctx->sh_video->stream_aspect = ar;
- }
- }
-#endif
-
-//================= Keyboard events, SEEKing ====================
-
- current_module="key_events";
-
-{
- while (1) {
- mp_cmd_t* cmd;
- while ((cmd = mp_input_get_cmd(mpctx->input, 0, 0)) != NULL) {
- run_command(mpctx, cmd);
- mp_cmd_free(cmd);
- if (mpctx->stop_play)
- break;
- if (mpctx->rel_seek_secs || mpctx->abs_seek_pos) {
- cmd = mp_input_get_cmd(mpctx->input, 0, 1);
- /* Allow seek commands to be combined, but execute the real seek
- * before processing other commands */
- if (!cmd || cmd->id != MP_CMD_SEEK)
- break;
- }
- }
- if (!mpctx->paused || mpctx->stop_play || mpctx->rel_seek_secs
- || mpctx->abs_seek_pos)
- break;
- if (mpctx->sh_video) {
- update_osd_msg(mpctx);
- int hack = vo_osd_changed(0);
- vo_osd_changed(hack);
- if (hack) {
- if (redraw_osd(mpctx->sh_video, mpctx->osd) < 0) {
- add_step_frame(mpctx);
- break;
- }
- else
- vo_osd_changed(0);
- }
- }
- pause_loop(mpctx);
- }
-}
-
-// handle -sstep
-if (step_sec > 0 && !mpctx->paused) {
- mpctx->osd_function=OSD_FFW;
- mpctx->rel_seek_secs+=step_sec;
-}
-
- edl_update(mpctx);
-
- /* Looping. */
- if(mpctx->stop_play==AT_END_OF_FILE && opts->loop_times>=0) {
- mp_msg(MSGT_CPLAYER,MSGL_V,"loop_times = %d\n", opts->loop_times);
-
- if(opts->loop_times>1) opts->loop_times--; else
- if(opts->loop_times==1) opts->loop_times=-1;
- play_n_frames=play_n_frames_mf;
- mpctx->stop_play=0;
- mpctx->abs_seek_pos=SEEK_ABSOLUTE; mpctx->rel_seek_secs=seek_to_sec;
- }
-
-if(mpctx->rel_seek_secs || mpctx->abs_seek_pos){
- seek(mpctx, mpctx->rel_seek_secs, mpctx->abs_seek_pos);
-
- mpctx->rel_seek_secs=0;
- mpctx->abs_seek_pos=0;
-}
-
-} // while(!mpctx->stop_play)
+ while (!mpctx->stop_play)
+ run_playloop(mpctx);
mp_msg(MSGT_GLOBAL,MSGL_V,"EOF code: %d \n",mpctx->stop_play);
diff --git a/options.h b/options.h
index 66048e77b2..12ac475f9e 100644
--- a/options.h
+++ b/options.h
@@ -47,6 +47,7 @@ typedef struct MPOpts {
int user_correct_pts;
int user_pts_assoc_mode;
int initial_audio_sync;
+ int hr_seek;
int autosync;
int softsleep;
int rtc;
diff --git a/osdep/keycodes.h b/osdep/keycodes.h
index 4d153a24aa..d197c8e3e9 100644
--- a/osdep/keycodes.h
+++ b/osdep/keycodes.h
@@ -94,4 +94,10 @@
#define KEY_INTERN (0x1000)
#define KEY_CLOSE_WIN (KEY_INTERN+0)
+/* Modifiers added to individual keys */
+#define KEY_MODIFIER_SHIFT 0x2000
+#define KEY_MODIFIER_CTRL 0x4000
+#define KEY_MODIFIER_ALT 0x8000
+#define KEY_MODIFIER_META 0x10000
+
#endif /* MPLAYER_KEYCODES_H */