mirror of
https://github.com/mpv-player/mpv
synced 2025-03-26 22:42:47 +01:00
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
This commit is contained in:
commit
0afb326035
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
||||
|
91
command.c
91
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,
|
||||
|
@ -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
|
||||
|
141
input/input.c
141
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;
|
||||
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(i = 0; key_names[i].name != NULL; i++) {
|
||||
if(key_names[i].key == key)
|
||||
return key_names[i].name;
|
||||
}
|
||||
for (int i = 0; key_names[i].name != NULL; i++) {
|
||||
if (strcasecmp(key_names[i].name, name) == 0)
|
||||
return key_names[i].key + modifiers;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
44
m_option.c
44
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
|
||||
|
14
m_option.h
14
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 */
|
||||
|
22
mp_core.h
22
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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user