1
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:
Uoti Urpala 2010-12-20 19:17:43 +02:00
commit 0afb326035
18 changed files with 800 additions and 481 deletions

@ -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),

@ -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

@ -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);
}
}

@ -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

@ -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 */

@ -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);

829
mplayer.c

File diff suppressed because it is too large Load Diff

@ -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 */