aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile9
-rw-r--r--cfg-mplayer.h10
-rw-r--r--command.c2
-rwxr-xr-xconfigure27
-rw-r--r--defaultopts.c2
-rw-r--r--etc/input.conf21
-rw-r--r--input/input.c318
-rw-r--r--input/input.h11
-rw-r--r--libao2/ao_pulse.c568
-rw-r--r--libao2/audio_out.c5
-rw-r--r--libao2/audio_out.h4
-rw-r--r--libao2/audio_out_internal.h4
-rw-r--r--libmpcodecs/img_format.c3
-rw-r--r--libmpcodecs/img_format.h5
-rw-r--r--libmpcodecs/mp_image.c4
-rw-r--r--libmpcodecs/vf_ass.c2
-rw-r--r--libmpcodecs/vf_vo.c202
-rw-r--r--libmpdemux/demux_lavf.c2
-rw-r--r--libvo/cocoa_common.h20
-rw-r--r--libvo/cocoa_common.m128
-rw-r--r--libvo/gl_common.c1
-rw-r--r--libvo/video_out.c10
-rw-r--r--libvo/video_out.h1
-rw-r--r--libvo/vo_quartz.c1371
-rw-r--r--libvo/vo_xv.c133
-rw-r--r--libvo/x11_common.c17
-rw-r--r--libvo/x11_common.h1
-rw-r--r--mixer.c24
-rw-r--r--mixer.h9
-rw-r--r--mp_core.h3
-rw-r--r--mp_msg.c4
-rw-r--r--mplayer.c661
-rw-r--r--options.h5
-rw-r--r--osdep/macosx_finder_args.c128
-rw-r--r--osdep/macosx_finder_args.h8
-rw-r--r--osdep/macosx_finder_args.m95
-rw-r--r--stream/stream_vstream.c5
-rw-r--r--sub/sub.h1
38 files changed, 1270 insertions, 2554 deletions
diff --git a/Makefile b/Makefile
index ae2267f5ec..cc5c75ef89 100644
--- a/Makefile
+++ b/Makefile
@@ -99,7 +99,7 @@ SRCS_COMMON-$(LIBTHEORA) += libmpcodecs/vd_theora.c
SRCS_COMMON-$(LIVE555) += libmpdemux/demux_rtp.cpp \
libmpdemux/demux_rtp_codec.cpp \
stream/stream_live555.c
-SRCS_COMMON-$(MACOSX_FINDER) += osdep/macosx_finder_args.c
+SRCS_COMMON-$(MACOSX_FINDER) += osdep/macosx_finder_args.m
SRCS_COMMON-$(MNG) += libmpdemux/demux_mng.c
SRCS_COMMON-$(MPG123) += libmpcodecs/ad_mpg123.c
@@ -416,12 +416,12 @@ SRCS_COMMON = asxparser.c \
stream/stream_null.c \
stream/url.c \
sub/av_sub.c \
- sub/sub.c \
- sub/sub_cc.c \
sub/dec_sub.c \
sub/find_sub.c \
sub/find_subfiles.c \
sub/spudec.c \
+ sub/sub.c \
+ sub/sub_cc.c \
sub/subassconvert.c \
sub/subreader.c \
sub/vobsub.c \
@@ -472,7 +472,6 @@ SRCS_MPLAYER-$(OPENAL) += libao2/ao_openal.c
SRCS_MPLAYER-$(OSS) += libao2/ao_oss.c
SRCS_MPLAYER-$(PNM) += libvo/vo_pnm.c
SRCS_MPLAYER-$(PULSE) += libao2/ao_pulse.c
-SRCS_MPLAYER-$(QUARTZ) += libvo/vo_quartz.c libvo/osx_common.c
SRCS_MPLAYER-$(RSOUND) += libao2/ao_rsound.c
SRCS_MPLAYER-$(S3FB) += libvo/vo_s3fb.c
SRCS_MPLAYER-$(SDL) += libao2/ao_sdl.c libvo/vo_sdl.c libvo/sdl_common.c
@@ -528,7 +527,7 @@ OBJS_MPLAYER-$(PE_EXECUTABLE) += osdep/mplayer-rc.o
OBJS_MPLAYER += $(OBJS_MPLAYER-yes)
MPLAYER_DEPS = $(OBJS_MPLAYER) $(OBJS_COMMON) $(COMMON_LIBS)
-DEP_FILES = $(patsubst %.S,%.d,$(patsubst %.cpp,%.d,$(patsubst %.c,%.d,$(SRCS_COMMON) $(SRCS_MPLAYER:.m=.d))))
+DEP_FILES = $(patsubst %.S,%.d,$(patsubst %.cpp,%.d,$(patsubst %.c,%.d,$(SRCS_COMMON:.m=.d) $(SRCS_MPLAYER:.m=.d))))
ALL_PRG-$(MPLAYER) += mplayer$(EXESUF)
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index 75aa5553fe..1d18949ce0 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -731,11 +731,10 @@ const m_option_t mplayer_opts[]={
{"border", &vo_border, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"noborder", &vo_border, CONF_TYPE_FLAG, 0, 1, 0, NULL},
- {"mixer", &mixer_device, CONF_TYPE_STRING, 0, 0, 0, NULL},
- {"mixer-channel", &mixer_channel, CONF_TYPE_STRING, 0, 0, 0, NULL},
- {"softvol", &soft_vol, CONF_TYPE_FLAG, 0, 0, 1, NULL},
- {"nosoftvol", &soft_vol, CONF_TYPE_FLAG, 0, 1, 0, NULL},
- {"softvol-max", &soft_vol_max, CONF_TYPE_FLOAT, CONF_RANGE, 10, 10000, NULL},
+ OPT_STRING("mixer", mixer_device, 0),
+ OPT_STRING("mixer-channel", mixer_channel, 0),
+ OPT_MAKE_FLAGS("softvol", softvol, 0),
+ OPT_FLOATRANGE("softvol-max", softvol_max, 0, 10, 10000),
{"volstep", &volstep, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL},
{"volume", &start_volume, CONF_TYPE_FLOAT, CONF_RANGE, -1, 10000, NULL},
OPT_MAKE_FLAGS("gapless-audio", gapless_audio, 0),
@@ -807,6 +806,7 @@ const m_option_t mplayer_opts[]={
{"grabpointer", &vo_grabpointer, CONF_TYPE_FLAG, 0, 0, 1, NULL},
{"nograbpointer", &vo_grabpointer, CONF_TYPE_FLAG, 0, 1, 0, NULL},
+ OPT_INTRANGE("cursor-autohide-delay", cursor_autohide_delay, 0, -2, 30000),
{"adapter", &vo_adapter_num, CONF_TYPE_INT, CONF_RANGE, 0, 5, NULL},
{"refreshrate",&vo_refresh_rate,CONF_TYPE_INT,CONF_RANGE, 0,100, NULL},
diff --git a/command.c b/command.c
index 68a575f1c0..b04fe09656 100644
--- a/command.c
+++ b/command.c
@@ -1764,7 +1764,7 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg,
}
#endif
- update_subtitles(mpctx, 0, 0, true);
+ update_subtitles(mpctx, 0, true);
return M_PROPERTY_OK;
}
diff --git a/configure b/configure
index 3731ba9458..7acd6bdfdd 100755
--- a/configure
+++ b/configure
@@ -438,7 +438,6 @@ Video output:
--disable-yuv4mpeg disable yuv4mpeg video output [enable]
--disable-corevideo disable CoreVideo video output [autodetect]
--disable-cocoa disable Cocoa OpenGL backend [autodetect]
- --disable-quartz disable Quartz video output [autodetect]
Audio output:
--disable-alsa disable ALSA audio output [autodetect]
@@ -701,7 +700,6 @@ _qtx=auto
_coreaudio=auto
_corevideo=auto
_cocoa=auto
-_quartz=auto
quicktime=auto
_macosx_finder=no
_macosx_bundle=auto
@@ -1139,8 +1137,6 @@ for ac_option do
--disable-corevideo) _corevideo=no ;;
--enable-cocoa) _cocoa=yes ;;
--disable-cocoa) _cocoa=no ;;
- --enable-quartz) _quartz=yes ;;
- --disable-quartz) _quartz=no ;;
--enable-macosx-finder) _macosx_finder=yes ;;
--disable-macosx-finder) _macosx_finder=no ;;
--enable-macosx-bundle) _macosx_bundle=yes ;;
@@ -3583,7 +3579,7 @@ echocheck "Mac OS X Finder Support"
def_macosx_finder='#undef CONFIG_MACOSX_FINDER'
if test "$_macosx_finder" = yes ; then
def_macosx_finder='#define CONFIG_MACOSX_FINDER 1'
- extra_ldflags="$extra_ldflags -framework Carbon"
+ extra_ldflags="$extra_ldflags -framework Cocoa"
fi
echores "$_macosx_finder"
@@ -3592,7 +3588,6 @@ def_macosx_bundle='#undef CONFIG_MACOSX_BUNDLE'
test "$_macosx_bundle" = auto && _macosx_bundle=$_macosx_finder
if test "$_macosx_bundle" = yes ; then
def_macosx_bundle='#define CONFIG_MACOSX_BUNDLE 1'
- extra_ldflags="$extra_ldflags -framework Carbon"
fi
echores "$_macosx_bundle"
@@ -4218,25 +4213,9 @@ if test "$quicktime" = yes ; then
def_quicktime='#define CONFIG_QUICKTIME 1'
else
def_quicktime='#undef CONFIG_QUICKTIME'
- _quartz=no
fi
echores $quicktime
-echocheck "Quartz"
-if test "$_quartz" = auto ; then
- _quartz=no
- statement_check Carbon/Carbon.h 'CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false)' -framework Carbon && _quartz=yes
-fi
-if test "$_quartz" = yes ; then
- libs_mplayer="$libs_mplayer -framework Carbon"
- def_quartz='#define CONFIG_QUARTZ 1'
- vomodules="quartz $vomodules"
-else
- def_quartz='#undef CONFIG_QUARTZ'
- novomodules="quartz $novomodules"
-fi
-echores $_quartz
-
echocheck "CoreVideo"
if test "$_corevideo" = auto ; then
cat > $TMPC <<EOF
@@ -4573,7 +4552,7 @@ int main(int argc, char *argv[]) {
EOF
_gl=no
for _ld_tmp in "" -lGL "-lGL -lXdamage" "-lGL $_ld_pthread" ; do
- if cc_check $_ld_tmp $_ld_lm ; then
+ if test "$_cocoa" != yes && cc_check $_ld_tmp $_ld_lm ; then
_gl=yes
_gl_x11=yes
libs_mplayer="$libs_mplayer $_ld_tmp $_ld_dl"
@@ -6563,7 +6542,6 @@ PVR = $_pvr
QTX_CODECS = $_qtx
QTX_CODECS_WIN32 = $_qtx_codecs_win32
QTX_EMULATION = $_qtx_emulation
-QUARTZ = $_quartz
RADIO=$_radio
RADIO_CAPTURE=$_radio_capture
REAL_CODECS = $_real
@@ -6930,7 +6908,6 @@ $def_mga
$def_mng
$def_png
$def_pnm
-$def_quartz
$def_s3fb
$def_sdl
$def_sdl_sdl_h
diff --git a/defaultopts.c b/defaultopts.c
index bf0489a335..8cb86c0457 100644
--- a/defaultopts.c
+++ b/defaultopts.c
@@ -10,9 +10,11 @@ void set_default_mplayer_options(struct MPOpts *opts)
.audio_driver_list = NULL,
.video_driver_list = NULL,
.fixed_vo = 1,
+ .softvol_max = 110,
.ao_buffersize = -1,
.monitor_pixel_aspect = 1.0,
.vo_panscanrange = 1.0,
+ .cursor_autohide_delay = 1000,
.vo_gamma_gamma = 1000,
.vo_gamma_brightness = 1000,
.vo_gamma_contrast = 1000,
diff --git a/etc/input.conf b/etc/input.conf
index b358d33243..7b61344f7f 100644
--- a/etc/input.conf
+++ b/etc/input.conf
@@ -33,16 +33,16 @@ MOUSE_BTN4 seek -10
MOUSE_BTN5 volume 1
MOUSE_BTN6 volume -1
-# Seek units are in seconds, but note that these are mostly limited by keyframes
-RIGHT seek 10
-LEFT seek -10
-UP seek 60
-DOWN seek -60
+# Seek units are in seconds, but note that these are limited by keyframes
+RIGHT seek 10
+LEFT seek -10
+UP seek 60
+DOWN 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+UP seek 5 0 1
-Shift+DOWN seek -5 0 1
+Shift+UP seek 5 0 1
+Shift+DOWN seek -5 0 1
PGUP seek 600
PGDWN seek -600
+ audio_delay 0.100 # this changes audio/video sync
@@ -87,9 +87,10 @@ m mute
7 saturation -1
8 saturation 1
d frame_drop # cycle through framedrop modes
-D step_property_osd deinterlace # toggle deinterlacer, requires -vf yadif or kerndeint
+# toggle deinterlacer; requires either vdpau output, -vf yadif or kerndeint
+D step_property_osd deinterlace
c step_property_osd colormatrix
-# These currently only work with --no-ass
+# Next 3 currently only work with --no-ass
r sub_pos -1 # move subtitles up
t sub_pos +1 # down
a sub_alignment
@@ -106,7 +107,7 @@ i edl_mark # for use with --edlout mode
T vo_ontop # toggle video window ontop of other windows
f vo_fullscreen # toggle fullscreen
C step_property_osd capturing
-s screenshot 0 # take a png screenshot with -vf screenshot
+s screenshot 0 # take a png screenshot
S screenshot 1 # ...on every frame
Alt+s screenshot 0 1 # take a screenshot of window contents
Alt+S screenshot 1 1 # ...on every frame
diff --git a/input/input.c b/input/input.c
index 008c908634..57b2d21f9d 100644
--- a/input/input.c
+++ b/input/input.c
@@ -71,150 +71,152 @@ struct key_name {
char *name;
};
-/// This array defines all known commands.
-/// The first field is an id used to recognize the command without too many strcmp.
-/// The second is obviously the command name.
-/// The third is the minimum number of arguments this command needs.
-/// Then comes the definition of each argument, terminated with an arg of
-/// type 0 (this doesn't need to be explicit, because C will default initialize
-/// the following arguments to type 0).
-/// A command can take a maximum of MP_CMD_MAX_ARGS-1 arguments (-1 because of
-/// the last one) which is actually 9.
-
-/// For the args, the first field is the type (actually int, float or string), the second
-/// is the default value wich is used for optional arguments
+/* This array defines all known commands.
+ * The first field is an id used to recognize the command.
+ * The second is the command name used in slave mode and input.conf.
+ * Then comes the definition of each argument, first mandatory arguments
+ * (ARG_INT, ARG_FLOAT, ARG_STRING) if any, then optional arguments
+ * (OARG_INT(default), etc) if any. The command will be given the default
+ * argument value if the user didn't give enough arguments to specify it.
+ * A command can take a maximum of MP_CMD_MAX_ARGS arguments (10).
+ */
+#define ARG_INT { .type = MP_CMD_ARG_INT }
+#define OARG_INT(def) { .type = MP_CMD_ARG_INT, .optional = true, .v.i = def }
+#define ARG_FLOAT { .type = MP_CMD_ARG_FLOAT }
+#define OARG_FLOAT(def) { .type = MP_CMD_ARG_FLOAT, .optional = true, .v.f = def }
+#define ARG_STRING { .type = MP_CMD_ARG_STRING }
+#define OARG_STRING(def) { .type = MP_CMD_ARG_STRING, .optional = true, .v.s = def }
static const mp_cmd_t mp_cmds[] = {
#ifdef CONFIG_RADIO
- { MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", 1, { { MP_CMD_ARG_INT} } },
- { MP_CMD_RADIO_SET_CHANNEL, "radio_set_channel", 1, { { MP_CMD_ARG_STRING} } },
- { MP_CMD_RADIO_SET_FREQ, "radio_set_freq", 1, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", 1, { {MP_CMD_ARG_FLOAT} } },
+ { MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", { ARG_INT } },
+ { MP_CMD_RADIO_SET_CHANNEL, "radio_set_channel", { ARG_STRING } },
+ { MP_CMD_RADIO_SET_FREQ, "radio_set_freq", { ARG_FLOAT } },
+ { MP_CMD_RADIO_STEP_FREQ, "radio_step_freq", {ARG_FLOAT } },
#endif
- { MP_CMD_SEEK, "seek", 1, { {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_EDL_MARK, "edl_mark", 0 },
- { MP_CMD_AUDIO_DELAY, "audio_delay", 1, { {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SPEED_INCR, "speed_incr", 1, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_SPEED_MULT, "speed_mult", 1, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_SPEED_SET, "speed_set", 1, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_QUIT, "quit", 0, { {MP_CMD_ARG_INT} } },
- { MP_CMD_STOP, "stop", 0 },
- { MP_CMD_PAUSE, "pause", 0 },
- { MP_CMD_FRAME_STEP, "frame_step", 0 },
- { MP_CMD_PLAY_TREE_STEP, "pt_step", 1, { { MP_CMD_ARG_INT }, { MP_CMD_ARG_INT } } },
- { MP_CMD_PLAY_TREE_UP_STEP, "pt_up_step", 1, { { MP_CMD_ARG_INT }, { MP_CMD_ARG_INT } } },
- { MP_CMD_PLAY_ALT_SRC_STEP, "alt_src_step", 1, { { MP_CMD_ARG_INT } } },
- { MP_CMD_LOOP, "loop", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SUB_DELAY, "sub_delay", 1, { {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SUB_STEP, "sub_step", 1, { { MP_CMD_ARG_INT }, {MP_CMD_ARG_INT} } },
- { MP_CMD_OSD, "osd", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_OSD_SHOW_TEXT, "osd_show_text", 1, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_INT, {.i = -1}}, {MP_CMD_ARG_INT} } },
- { MP_CMD_OSD_SHOW_PROPERTY_TEXT, "osd_show_property_text",1, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_INT, {.i = -1}}, {MP_CMD_ARG_INT} } },
- { MP_CMD_OSD_SHOW_PROGRESSION, "osd_show_progression", 0 },
- { MP_CMD_VOLUME, "volume", 1, { { MP_CMD_ARG_FLOAT }, {MP_CMD_ARG_INT} } },
- { MP_CMD_BALANCE, "balance", 1, { { MP_CMD_ARG_FLOAT }, {MP_CMD_ARG_INT} } },
- { MP_CMD_MIXER_USEMASTER, "use_master", 0 },
- { MP_CMD_MUTE, "mute", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_CONTRAST, "contrast", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_GAMMA, "gamma", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_BRIGHTNESS, "brightness", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_HUE, "hue", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SATURATION, "saturation", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_FRAMEDROPPING, "frame_drop", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SUB_POS, "sub_pos", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SUB_ALIGNMENT, "sub_alignment", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SUB_VISIBILITY, "sub_visibility", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SUB_LOAD, "sub_load", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_SUB_REMOVE, "sub_remove", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SUB_SELECT, "vobsub_lang", 0, { { MP_CMD_ARG_INT, {.i = -2}} } }, // for compatibility
- { MP_CMD_SUB_SELECT, "sub_select", 0, { { MP_CMD_ARG_INT, {.i = -2}} } },
- { MP_CMD_SUB_SOURCE, "sub_source", 0, { { MP_CMD_ARG_INT, {.i = -2}} } },
- { MP_CMD_SUB_VOB, "sub_vob", 0, { { MP_CMD_ARG_INT, {.i = -2}} } },
- { MP_CMD_SUB_DEMUX, "sub_demux", 0, { { MP_CMD_ARG_INT, {.i = -2}} } },
- { MP_CMD_SUB_FILE, "sub_file", 0, { { MP_CMD_ARG_INT, {.i = -2}} } },
- { MP_CMD_SUB_LOG, "sub_log", 0 },
- { MP_CMD_SUB_SCALE, "sub_scale", 1, { {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT} } },
+ { MP_CMD_SEEK, "seek", { ARG_FLOAT, OARG_INT(0), OARG_INT(0) } },
+ { MP_CMD_EDL_MARK, "edl_mark", },
+ { MP_CMD_AUDIO_DELAY, "audio_delay", { ARG_FLOAT, OARG_INT(0) } },
+ { MP_CMD_SPEED_INCR, "speed_incr", { ARG_FLOAT } },
+ { MP_CMD_SPEED_MULT, "speed_mult", { ARG_FLOAT } },
+ { MP_CMD_SPEED_SET, "speed_set", { ARG_FLOAT } },
+ { MP_CMD_QUIT, "quit", { OARG_INT(0) } },
+ { MP_CMD_STOP, "stop", },
+ { MP_CMD_PAUSE, "pause", },
+ { MP_CMD_FRAME_STEP, "frame_step", },
+ { MP_CMD_PLAY_TREE_STEP, "pt_step", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_PLAY_TREE_UP_STEP, "pt_up_step", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_PLAY_ALT_SRC_STEP, "alt_src_step", { ARG_INT } },
+ { MP_CMD_LOOP, "loop", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_SUB_DELAY, "sub_delay", { ARG_FLOAT, OARG_INT(0) } },
+ { MP_CMD_SUB_STEP, "sub_step", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_OSD, "osd", { OARG_INT(-1) } },
+ { MP_CMD_OSD_SHOW_TEXT, "osd_show_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } },
+ { MP_CMD_OSD_SHOW_PROPERTY_TEXT, "osd_show_property_text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) } },
+ { MP_CMD_OSD_SHOW_PROGRESSION, "osd_show_progression", },
+ { MP_CMD_VOLUME, "volume", { ARG_FLOAT, OARG_INT(0) } },
+ { MP_CMD_BALANCE, "balance", { ARG_FLOAT, OARG_INT(0) } },
+ { MP_CMD_MIXER_USEMASTER, "use_master", },
+ { MP_CMD_MUTE, "mute", { OARG_INT(-1) } },
+ { MP_CMD_CONTRAST, "contrast", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_GAMMA, "gamma", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_BRIGHTNESS, "brightness", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_HUE, "hue", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_SATURATION, "saturation", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_FRAMEDROPPING, "frame_drop", { OARG_INT(-1) } },
+ { MP_CMD_SUB_POS, "sub_pos", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_SUB_ALIGNMENT, "sub_alignment", { OARG_INT(-1) } },
+ { MP_CMD_SUB_VISIBILITY, "sub_visibility", { OARG_INT(-1) } },
+ { MP_CMD_SUB_LOAD, "sub_load", { ARG_STRING } },
+ { MP_CMD_SUB_REMOVE, "sub_remove", { OARG_INT(-1) } },
+ { MP_CMD_SUB_SELECT, "vobsub_lang", { OARG_INT(-2) } }, // for compatibility
+ { MP_CMD_SUB_SELECT, "sub_select", { OARG_INT(-2) } },
+ { MP_CMD_SUB_SOURCE, "sub_source", { OARG_INT(-2) } },
+ { MP_CMD_SUB_VOB, "sub_vob", { OARG_INT(-2) } },
+ { MP_CMD_SUB_DEMUX, "sub_demux", { OARG_INT(-2) } },
+ { MP_CMD_SUB_FILE, "sub_file", { OARG_INT(-2) } },
+ { MP_CMD_SUB_LOG, "sub_log", },
+ { MP_CMD_SUB_SCALE, "sub_scale", { ARG_FLOAT, OARG_INT(0) } },
#ifdef CONFIG_ASS
- { MP_CMD_ASS_USE_MARGINS, "ass_use_margins", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
+ { MP_CMD_ASS_USE_MARGINS, "ass_use_margins", { OARG_INT(-1) } },
#endif
- { MP_CMD_GET_PERCENT_POS, "get_percent_pos", 0 },
- { MP_CMD_GET_TIME_POS, "get_time_pos", 0 },
- { MP_CMD_GET_TIME_LENGTH, "get_time_length", 0 },
- { MP_CMD_GET_FILENAME, "get_file_name", 0 },
- { MP_CMD_GET_VIDEO_CODEC, "get_video_codec", 0 },
- { MP_CMD_GET_VIDEO_BITRATE, "get_video_bitrate", 0 },
- { MP_CMD_GET_VIDEO_RESOLUTION, "get_video_resolution", 0 },
- { MP_CMD_GET_AUDIO_CODEC, "get_audio_codec", 0 },
- { MP_CMD_GET_AUDIO_BITRATE, "get_audio_bitrate", 0 },
- { MP_CMD_GET_AUDIO_SAMPLES, "get_audio_samples", 0 },
- { MP_CMD_GET_META_TITLE, "get_meta_title", 0 },
- { MP_CMD_GET_META_ARTIST, "get_meta_artist", 0 },
- { MP_CMD_GET_META_ALBUM, "get_meta_album", 0 },
- { MP_CMD_GET_META_YEAR, "get_meta_year", 0 },
- { MP_CMD_GET_META_COMMENT, "get_meta_comment", 0 },
- { MP_CMD_GET_META_TRACK, "get_meta_track", 0 },
- { MP_CMD_GET_META_GENRE, "get_meta_genre", 0 },
- { MP_CMD_SWITCH_AUDIO, "switch_audio", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SWITCH_ANGLE, "switch_angle", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SWITCH_TITLE, "switch_title", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
+ { MP_CMD_GET_PERCENT_POS, "get_percent_pos", },
+ { MP_CMD_GET_TIME_POS, "get_time_pos", },
+ { MP_CMD_GET_TIME_LENGTH, "get_time_length", },
+ { MP_CMD_GET_FILENAME, "get_file_name", },
+ { MP_CMD_GET_VIDEO_CODEC, "get_video_codec", },
+ { MP_CMD_GET_VIDEO_BITRATE, "get_video_bitrate", },
+ { MP_CMD_GET_VIDEO_RESOLUTION, "get_video_resolution", },
+ { MP_CMD_GET_AUDIO_CODEC, "get_audio_codec", },
+ { MP_CMD_GET_AUDIO_BITRATE, "get_audio_bitrate", },
+ { MP_CMD_GET_AUDIO_SAMPLES, "get_audio_samples", },
+ { MP_CMD_GET_META_TITLE, "get_meta_title", },
+ { MP_CMD_GET_META_ARTIST, "get_meta_artist", },
+ { MP_CMD_GET_META_ALBUM, "get_meta_album", },
+ { MP_CMD_GET_META_YEAR, "get_meta_year", },
+ { MP_CMD_GET_META_COMMENT, "get_meta_comment", },
+ { MP_CMD_GET_META_TRACK, "get_meta_track", },
+ { MP_CMD_GET_META_GENRE, "get_meta_genre", },
+ { MP_CMD_SWITCH_AUDIO, "switch_audio", { OARG_INT(-1) } },
+ { MP_CMD_SWITCH_ANGLE, "switch_angle", { OARG_INT(-1) } },
+ { MP_CMD_SWITCH_TITLE, "switch_title", { OARG_INT(-1) } },
#ifdef CONFIG_TV
- { MP_CMD_TV_START_SCAN, "tv_start_scan", 0 },
- { MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", 1, { {MP_CMD_ARG_INT} } },
- { MP_CMD_TV_STEP_NORM, "tv_step_norm", 0 },
- { MP_CMD_TV_STEP_CHANNEL_LIST, "tv_step_chanlist", 0 },
- { MP_CMD_TV_SET_CHANNEL, "tv_set_channel", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_TV_LAST_CHANNEL, "tv_last_channel", 0 },
- { MP_CMD_TV_SET_FREQ, "tv_set_freq", 1, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_TV_STEP_FREQ, "tv_step_freq", 1, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_TV_SET_NORM, "tv_set_norm", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_TV_SET_BRIGHTNESS, "tv_set_brightness", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT, {.i = 1}} } },
- { MP_CMD_TV_SET_CONTRAST, "tv_set_contrast", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT, {.i = 1}} } },
- { MP_CMD_TV_SET_HUE, "tv_set_hue", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT, {.i = 1}} } },
- { MP_CMD_TV_SET_SATURATION, "tv_set_saturation", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT, {.i = 1}} } },
+ { MP_CMD_TV_START_SCAN, "tv_start_scan", },
+ { MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", { ARG_INT } },
+ { MP_CMD_TV_STEP_NORM, "tv_step_norm", },
+ { MP_CMD_TV_STEP_CHANNEL_LIST, "tv_step_chanlist", },
+ { MP_CMD_TV_SET_CHANNEL, "tv_set_channel", { ARG_STRING } },
+ { MP_CMD_TV_LAST_CHANNEL, "tv_last_channel", },
+ { MP_CMD_TV_SET_FREQ, "tv_set_freq", { ARG_FLOAT } },
+ { MP_CMD_TV_STEP_FREQ, "tv_step_freq", { ARG_FLOAT } },
+ { MP_CMD_TV_SET_NORM, "tv_set_norm", { ARG_STRING } },
+ { MP_CMD_TV_SET_BRIGHTNESS, "tv_set_brightness", { ARG_INT, OARG_INT(1) } },
+ { MP_CMD_TV_SET_CONTRAST, "tv_set_contrast", { ARG_INT, OARG_INT(1) } },
+ { MP_CMD_TV_SET_HUE, "tv_set_hue", { ARG_INT, OARG_INT(1) } },
+ { MP_CMD_TV_SET_SATURATION, "tv_set_saturation", { ARG_INT, OARG_INT(1) } },
#endif
- { MP_CMD_SUB_FORCED_ONLY, "forced_subs_only", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
+ { MP_CMD_SUB_FORCED_ONLY, "forced_subs_only", { OARG_INT(-1) } },
#ifdef CONFIG_DVBIN
- { MP_CMD_DVB_SET_CHANNEL, "dvb_set_channel", 2, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
+ { MP_CMD_DVB_SET_CHANNEL, "dvb_set_channel", { ARG_INT, ARG_INT } },
#endif
- { MP_CMD_SWITCH_RATIO, "switch_ratio", 0, { {MP_CMD_ARG_FLOAT} } },
- { MP_CMD_VO_FULLSCREEN, "vo_fullscreen", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_VO_ONTOP, "vo_ontop", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_VO_ROOTWIN, "vo_rootwin", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_VO_BORDER, "vo_border", 0, { {MP_CMD_ARG_INT, {.i = -1}} } },
- { MP_CMD_SCREENSHOT, "screenshot", 0, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_PANSCAN, "panscan",1, { {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SWITCH_VSYNC, "switch_vsync", 0, { {MP_CMD_ARG_INT} } },
- { MP_CMD_LOADFILE, "loadfile", 1, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_INT} } },
- { MP_CMD_LOADLIST, "loadlist", 1, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_INT} } },
- { MP_CMD_PLAY_TREE_CLEAR, "pt_clear", 0 },
- { MP_CMD_RUN, "run", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_CAPTURING, "capturing", 0 },
- { MP_CMD_VF_CHANGE_RECTANGLE, "change_rectangle", 2, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_TV_TELETEXT_ADD_DEC, "teletext_add_dec", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_TV_TELETEXT_GO_LINK, "teletext_go_link", 1, { {MP_CMD_ARG_INT} } },
+ { MP_CMD_SWITCH_RATIO, "switch_ratio", { OARG_FLOAT(0) } },
+ { MP_CMD_VO_FULLSCREEN, "vo_fullscreen", { OARG_INT(-1) } },
+ { MP_CMD_VO_ONTOP, "vo_ontop", { OARG_INT(-1) } },
+ { MP_CMD_VO_ROOTWIN, "vo_rootwin", { OARG_INT(-1) } },
+ { MP_CMD_VO_BORDER, "vo_border", { OARG_INT(-1) } },
+ { MP_CMD_SCREENSHOT, "screenshot", { OARG_INT(0), OARG_INT(0) } },
+ { MP_CMD_PANSCAN, "panscan", { ARG_FLOAT, OARG_INT(0) } },
+ { MP_CMD_SWITCH_VSYNC, "switch_vsync", { OARG_INT(0) } },
+ { MP_CMD_LOADFILE, "loadfile", { ARG_STRING, OARG_INT(0) } },
+ { MP_CMD_LOADLIST, "loadlist", { ARG_STRING, OARG_INT(0) } },
+ { MP_CMD_PLAY_TREE_CLEAR, "pt_clear", },
+ { MP_CMD_RUN, "run", { ARG_STRING } },
+ { MP_CMD_CAPTURING, "capturing", },
+ { MP_CMD_VF_CHANGE_RECTANGLE, "change_rectangle", { ARG_INT, ARG_INT } },
+ { MP_CMD_TV_TELETEXT_ADD_DEC, "teletext_add_dec", { ARG_STRING } },
+ { MP_CMD_TV_TELETEXT_GO_LINK, "teletext_go_link", { ARG_INT } },
#ifdef CONFIG_DVDNAV
- { MP_CMD_DVDNAV, "dvdnav", 1, { {MP_CMD_ARG_STRING} } },
+ { MP_CMD_DVDNAV, "dvdnav", { ARG_STRING } },
#endif
- { MP_CMD_GET_VO_FULLSCREEN, "get_vo_fullscreen", 0 },
- { MP_CMD_GET_SUB_VISIBILITY, "get_sub_visibility", 0 },
- { MP_CMD_KEYDOWN_EVENTS, "key_down_event", 1, { {MP_CMD_ARG_INT} } },
- { MP_CMD_SET_PROPERTY, "set_property", 2, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_STRING} } },
- { MP_CMD_SET_PROPERTY_OSD, "set_property_osd", 2, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_STRING} } },
- { MP_CMD_GET_PROPERTY, "get_property", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_STEP_PROPERTY, "step_property", 1, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_STEP_PROPERTY_OSD, "step_property_osd", 1, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_FLOAT}, {MP_CMD_ARG_INT} } },
-
- { MP_CMD_SEEK_CHAPTER, "seek_chapter", 1, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
- { MP_CMD_SET_MOUSE_POS, "set_mouse_pos", 2, { {MP_CMD_ARG_INT}, {MP_CMD_ARG_INT} } },
-
- { MP_CMD_AF_SWITCH, "af_switch", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_AF_ADD, "af_add", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_AF_DEL, "af_del", 1, { {MP_CMD_ARG_STRING} } },
- { MP_CMD_AF_CLR, "af_clr", 0 },
- { MP_CMD_AF_CMDLINE, "af_cmdline", 2, { {MP_CMD_ARG_STRING}, {MP_CMD_ARG_STRING} } },
-
+ { MP_CMD_GET_VO_FULLSCREEN, "get_vo_fullscreen", },
+ { MP_CMD_GET_SUB_VISIBILITY, "get_sub_visibility", },
+ { MP_CMD_KEYDOWN_EVENTS, "key_down_event", { ARG_INT } },
+ { MP_CMD_SET_PROPERTY, "set_property", { ARG_STRING, ARG_STRING } },
+ { MP_CMD_SET_PROPERTY_OSD, "set_property_osd", { ARG_STRING, ARG_STRING } },
+ { MP_CMD_GET_PROPERTY, "get_property", { ARG_STRING } },
+ { MP_CMD_STEP_PROPERTY, "step_property", { ARG_STRING, OARG_FLOAT(0), OARG_INT(0) } },
+ { MP_CMD_STEP_PROPERTY_OSD, "step_property_osd", { ARG_STRING, OARG_FLOAT(0), OARG_INT(0) } },
+
+ { MP_CMD_SEEK_CHAPTER, "seek_chapter", { ARG_INT, OARG_INT(0) } },
+ { MP_CMD_SET_MOUSE_POS, "set_mouse_pos", { ARG_INT, ARG_INT } },
+
+ { MP_CMD_AF_SWITCH, "af_switch", { ARG_STRING } },
+ { MP_CMD_AF_ADD, "af_add", { ARG_STRING } },
+ { MP_CMD_AF_DEL, "af_del", { ARG_STRING } },
+ { MP_CMD_AF_CLR, "af_clr", },
+ { MP_CMD_AF_CMDLINE, "af_cmdline", { ARG_STRING, ARG_STRING } },
{0}
};
@@ -618,6 +620,8 @@ struct input_ctx {
struct cmd_queue key_cmd_queue;
struct cmd_queue control_cmd_queue;
+
+ int wakeup_pipe[2];
};
@@ -990,10 +994,14 @@ mp_cmd_t *mp_input_parse_cmd(char *str)
}
cmd->nargs = i;
- if (cmd_def->nargs > cmd->nargs) {
- mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s requires at least %d "
+ int min_args;
+ for (min_args = 0; min_args < MP_CMD_MAX_ARGS
+ && cmd_def->args[min_args].type
+ && !cmd_def->args[min_args].optional; min_args++);
+ if (cmd->nargs < min_args) {
+ mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command \"%s\" requires at least %d "
"arguments, we found only %d so far.\n", cmd_def->name,
- cmd_def->nargs, cmd->nargs);
+ min_args, cmd->nargs);
goto error;
}
@@ -1116,6 +1124,13 @@ static int default_cmd_func(int fd, char *buf, int l)
}
}
+static int read_wakeup(void *ctx, int fd)
+{
+ char buf[100];
+ read(fd, buf, sizeof(buf));
+ return MP_INPUT_NOTHING;
+}
+
static char *find_bind_for_key(const struct cmd_bind *binds, int n, int *keys)
{
@@ -1138,7 +1153,7 @@ static char *find_bind_for_key(const struct cmd_bind *binds, int n, int *keys)
}
static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx,
- char *section)
+ char *section)
{
struct cmd_bind_section *bind_section = ictx->cmd_bind_sections;
@@ -1743,8 +1758,25 @@ struct input_ctx *mp_input_init(struct input_conf *input_conf)
.ar_delay = input_conf->ar_delay,
.ar_rate = input_conf->ar_rate,
.default_bindings = input_conf->default_bindings,
+ .wakeup_pipe = {-1, -1},
};
+#ifndef __MINGW32__
+ long ret = pipe(ictx->wakeup_pipe);
+ for (int i = 0; i < 2 && ret >= 0; i++) {
+ ret = fcntl(ictx->wakeup_pipe[i], F_GETFL);
+ if (ret < 0)
+ break;
+ ret = fcntl(ictx->wakeup_pipe[i], F_SETFL, ret | O_NONBLOCK);
+ }
+ if (ret < 0)
+ mp_msg(MSGT_INPUT, MSGL_ERR,
+ "Failed to initialize wakeup pipe: %s\n", strerror(errno));
+ else
+ mp_input_add_key_fd(ictx, ictx->wakeup_pipe[0], true, read_wakeup,
+ NULL, NULL);
+#endif
+
char *file;
char *config_file = input_conf->config_file;
file = config_file[0] != '/' ? get_path(config_file) : config_file;
@@ -1842,17 +1874,17 @@ void mp_input_uninit(struct input_ctx *ictx)
if (!ictx)
return;
- unsigned int i;
-
- for (i = 0; i < ictx->num_key_fd; i++) {
+ for (int i = 0; i < ictx->num_key_fd; i++) {
if (ictx->key_fds[i].close_func)
ictx->key_fds[i].close_func(ictx->key_fds[i].fd);
}
-
- for (i = 0; i < ictx->num_cmd_fd; i++) {
+ for (int i = 0; i < ictx->num_cmd_fd; i++) {
if (ictx->cmd_fds[i].close_func)
ictx->cmd_fds[i].close_func(ictx->cmd_fds[i].fd);
}
+ for (int i = 0; i < 2; i++)
+ if (ictx->wakeup_pipe[i] != -1)
+ close(ictx->wakeup_pipe[i]);
talloc_free(ictx);
}
@@ -1892,7 +1924,7 @@ static int print_cmd_list(m_option_t *cfg)
default:
type = "??";
}
- if (j + 1 > cmd->nargs)
+ if (cmd->args[j].optional)
printf(" [%s]", type);
else
printf(" %s", type);
@@ -1902,6 +1934,12 @@ static int print_cmd_list(m_option_t *cfg)
exit(0);
}
+void mp_input_wakeup(struct input_ctx *ictx)
+{
+ if (ictx->wakeup_pipe[1] >= 0)
+ write(ictx->wakeup_pipe[1], &(char){0}, 1);
+}
+
/**
* \param time time to wait for an interruption in milliseconds
*/
diff --git a/input/input.h b/input/input.h
index 084e2dd3e7..87814dd56c 100644
--- a/input/input.h
+++ b/input/input.h
@@ -19,6 +19,8 @@
#ifndef MPLAYER_INPUT_H
#define MPLAYER_INPUT_H
+#include <stdbool.h>
+
// All command IDs
enum mp_command_type {
MP_CMD_SEEK,
@@ -154,14 +156,11 @@ enum mp_command_type {
};
// The arg types
-#define MP_CMD_ARG_VOID 0
#define MP_CMD_ARG_INT 1
#define MP_CMD_ARG_FLOAT 2
#define MP_CMD_ARG_STRING 3
-#ifndef MP_CMD_MAX_ARGS
#define MP_CMD_MAX_ARGS 10
-#endif
// Error codes for the drivers
@@ -181,6 +180,7 @@ struct input_ctx;
struct mp_cmd_arg {
int type;
+ bool optional;
union {
int i;
float f;
@@ -191,8 +191,8 @@ struct mp_cmd_arg {
typedef struct mp_cmd {
int id;
char *name;
- int nargs;
struct mp_cmd_arg args[MP_CMD_MAX_ARGS];
+ int nargs;
int pausing;
struct mp_cmd *queue_next;
} mp_cmd_t;
@@ -272,6 +272,9 @@ void mp_input_uninit(struct input_ctx *ictx);
struct m_config;
void mp_input_register_options(struct m_config *cfg);
+// Wake up sleeping input loop from another thread.
+void mp_input_wakeup(struct input_ctx *ictx);
+
// Interruptible usleep: (used by libmpdemux)
int mp_input_check_interrupt(struct input_ctx *ictx, int time);
diff --git a/libao2/ao_pulse.c b/libao2/ao_pulse.c
index 24a448b5f9..5e71f7bf7e 100644
--- a/libao2/ao_pulse.c
+++ b/libao2/ao_pulse.c
@@ -20,6 +20,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
@@ -29,67 +31,80 @@
#include "libaf/af_format.h"
#include "mp_msg.h"
#include "audio_out.h"
-#include "audio_out_internal.h"
+#include "input/input.h"
-#define PULSE_CLIENT_NAME "MPlayer"
+#define PULSE_CLIENT_NAME "mplayer2"
-/** General driver info */
-static const ao_info_t info = {
- "PulseAudio audio output",
- "pulse",
- "Lennart Poettering",
- ""
-};
-/** PulseAudio playback stream object */
-static struct pa_stream *stream;
+struct priv {
+ // PulseAudio playback stream object
+ struct pa_stream *stream;
-/** PulseAudio connection context */
-static struct pa_context *context;
+ // PulseAudio connection context
+ struct pa_context *context;
-/** Main event loop object */
-static struct pa_threaded_mainloop *mainloop;
+ // Main event loop object
+ struct pa_threaded_mainloop *mainloop;
-static int broken_pause;
+ // temporary during control()
+ struct pa_sink_input_info pi;
-LIBAO_EXTERN(pulse)
+ bool broken_pause;
+ int retval;
+ bool did_reset;
+};
#define GENERIC_ERR_MSG(ctx, str) \
mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] "str": %s\n", \
- pa_strerror(pa_context_errno(ctx)))
+ pa_strerror(pa_context_errno(ctx)))
-static void context_state_cb(pa_context *c, void *userdata) {
+static void context_state_cb(pa_context *c, void *userdata)
+{
+ struct ao *ao = userdata;
+ struct priv *priv = ao->priv;
switch (pa_context_get_state(c)) {
- case PA_CONTEXT_READY:
- case PA_CONTEXT_TERMINATED:
- case PA_CONTEXT_FAILED:
- pa_threaded_mainloop_signal(mainloop, 0);
- break;
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal(priv->mainloop, 0);
+ break;
}
}
-static void stream_state_cb(pa_stream *s, void *userdata) {
+static void stream_state_cb(pa_stream *s, void *userdata)
+{
+ struct ao *ao = userdata;
+ struct priv *priv = ao->priv;
switch (pa_stream_get_state(s)) {
- case PA_STREAM_READY:
- case PA_STREAM_FAILED:
- case PA_STREAM_TERMINATED:
- pa_threaded_mainloop_signal(mainloop, 0);
- break;
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal(priv->mainloop, 0);
+ break;
}
}
-static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
- pa_threaded_mainloop_signal(mainloop, 0);
+static void stream_request_cb(pa_stream *s, size_t length, void *userdata)
+{
+ struct ao *ao = userdata;
+ struct priv *priv = ao->priv;
+ mp_input_wakeup(ao->input_ctx);
+ pa_threaded_mainloop_signal(priv->mainloop, 0);
}
-static void stream_latency_update_cb(pa_stream *s, void *userdata) {
- pa_threaded_mainloop_signal(mainloop, 0);
+static void stream_latency_update_cb(pa_stream *s, void *userdata)
+{
+ struct ao *ao = userdata;
+ struct priv *priv = ao->priv;
+ pa_threaded_mainloop_signal(priv->mainloop, 0);
}
-static void success_cb(pa_stream *s, int success, void *userdata) {
- if (userdata)
- *(int *)userdata = success;
- pa_threaded_mainloop_signal(mainloop, 0);
+static void success_cb(pa_stream *s, int success, void *userdata)
+{
+ struct ao *ao = userdata;
+ struct priv *priv = ao->priv;
+ priv->retval = success;
+ pa_threaded_mainloop_signal(priv->mainloop, 0);
}
/**
@@ -98,85 +113,116 @@ static void success_cb(pa_stream *s, int success, void *userdata) {
* \param op operation to wait for
* \return 1 if operation has finished normally (DONE state), 0 otherwise
*/
-static int waitop(pa_operation *op) {
- pa_operation_state_t state;
+static int waitop(struct priv *priv, pa_operation *op)
+{
if (!op) {
- pa_threaded_mainloop_unlock(mainloop);
+ pa_threaded_mainloop_unlock(priv->mainloop);
return 0;
}
- state = pa_operation_get_state(op);
+ pa_operation_state_t state = pa_operation_get_state(op);
while (state == PA_OPERATION_RUNNING) {
- pa_threaded_mainloop_wait(mainloop);
+ pa_threaded_mainloop_wait(priv->mainloop);
state = pa_operation_get_state(op);
}
pa_operation_unref(op);
- pa_threaded_mainloop_unlock(mainloop);
+ pa_threaded_mainloop_unlock(priv->mainloop);
return state == PA_OPERATION_DONE;
}
-static const struct format_map_s {
+static const struct format_map {
int mp_format;
pa_sample_format_t pa_format;
} format_maps[] = {
{AF_FORMAT_S16_LE, PA_SAMPLE_S16LE},
{AF_FORMAT_S16_BE, PA_SAMPLE_S16BE},
-#ifdef PA_SAMPLE_S32NE
{AF_FORMAT_S32_LE, PA_SAMPLE_S32LE},
{AF_FORMAT_S32_BE, PA_SAMPLE_S32BE},
-#endif
-#ifdef PA_SAMPLE_FLOAT32NE
{AF_FORMAT_FLOAT_LE, PA_SAMPLE_FLOAT32LE},
{AF_FORMAT_FLOAT_BE, PA_SAMPLE_FLOAT32BE},
-#endif
{AF_FORMAT_U8, PA_SAMPLE_U8},
{AF_FORMAT_MU_LAW, PA_SAMPLE_ULAW},
{AF_FORMAT_A_LAW, PA_SAMPLE_ALAW},
{AF_FORMAT_UNKNOWN, 0}
};
-static int init(int rate_hz, int channels, int format, int flags) {
+static void uninit(struct ao *ao, bool cut_audio)
+{
+ struct priv *priv = ao->priv;
+ if (priv->stream && !cut_audio) {
+ pa_threaded_mainloop_lock(priv->mainloop);
+ waitop(priv, pa_stream_drain(priv->stream, success_cb, ao));
+ }
+
+ if (priv->mainloop)
+ pa_threaded_mainloop_stop(priv->mainloop);
+
+ if (priv->stream) {
+ pa_stream_disconnect(priv->stream);
+ pa_stream_unref(priv->stream);
+ priv->stream = NULL;
+ }
+
+ if (priv->context) {
+ pa_context_disconnect(priv->context);
+ pa_context_unref(priv->context);
+ priv->context = NULL;
+ }
+
+ if (priv->mainloop) {
+ pa_threaded_mainloop_free(priv->mainloop);
+ priv->mainloop = NULL;
+ }
+}
+
+static int init(struct ao *ao, char *params)
+{
struct pa_sample_spec ss;
struct pa_channel_map map;
- const struct format_map_s *fmt_map;
char *devarg = NULL;
char *host = NULL;
char *sink = NULL;
const char *version = pa_get_library_version();
- if (ao_subdevice) {
+ struct priv *priv = talloc_zero(ao, struct priv);
+ ao->priv = priv;
+
+ if (params) {
devarg = strdup(ao_subdevice);
sink = strchr(devarg, ':');
- if (sink) *sink++ = 0;
- if (devarg[0]) host = devarg;
+ if (sink)
+ *sink++ = 0;
+ if (devarg[0])
+ host = devarg;
}
- broken_pause = 0;
- // not sure which versions are affected, assume 0.9.11* to 0.9.14*
- // known bad: 0.9.14, 0.9.13
- // known good: 0.9.9, 0.9.10, 0.9.15
- // to test: pause, wait ca. 5 seconds framestep and see if MPlayer hangs somewhen
- if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1' && version[5] <= '4') {
- mp_msg(MSGT_AO, MSGL_WARN, "[pulse] working around probably broken pause functionality,\n"
- " see http://www.pulseaudio.org/ticket/440\n");
- broken_pause = 1;
+ priv->broken_pause = false;
+ /* not sure which versions are affected, assume 0.9.11* to 0.9.14*
+ * known bad: 0.9.14, 0.9.13
+ * known good: 0.9.9, 0.9.10, 0.9.15
+ * To test: pause, wait ca. 5 seconds, framestep and see if MPlayer
+ * hangs somewhen. */
+ if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1'
+ && version[5] <= '4') {
+ mp_msg(MSGT_AO, MSGL_WARN,
+ "[pulse] working around probably broken pause functionality,\n"
+ " see http://www.pulseaudio.org/ticket/440\n");
+ priv->broken_pause = true;
}
- ss.channels = channels;
- ss.rate = rate_hz;
-
- ao_data.samplerate = rate_hz;
- ao_data.channels = channels;
+ ss.channels = ao->channels;
+ ss.rate = ao->samplerate;
- fmt_map = format_maps;
- while (fmt_map->mp_format != format) {
+ const struct format_map *fmt_map = format_maps;
+ while (fmt_map->mp_format != ao->format) {
if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) {
- mp_msg(MSGT_AO, MSGL_V, "AO: [pulse] Unsupported format, using default\n");
+ mp_msg(MSGT_AO, MSGL_V,
+ "AO: [pulse] Unsupported format, using default\n");
fmt_map = format_maps;
break;
}
fmt_map++;
}
- ao_data.format = fmt_map->mp_format;
+ ao->format = fmt_map->mp_format;
ss.format = fmt_map->pa_format;
if (!pa_sample_spec_valid(&ss)) {
@@ -185,245 +231,295 @@ static int init(int rate_hz, int channels, int format, int flags) {
}
pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA);
- ao_data.bps = pa_bytes_per_second(&ss);
+ ao->bps = pa_bytes_per_second(&ss);
- if (!(mainloop = pa_threaded_mainloop_new())) {
+ if (!(priv->mainloop = pa_threaded_mainloop_new())) {
mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n");
goto fail;
}
- if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) {
+ if (!(priv->context = pa_context_new(pa_threaded_mainloop_get_api(
+ priv->mainloop), PULSE_CLIENT_NAME))) {
mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n");
goto fail;
}
- pa_context_set_state_callback(context, context_state_cb, NULL);
+ pa_context_set_state_callback(priv->context, context_state_cb, ao);
- if (pa_context_connect(context, host, 0, NULL) < 0)
+ if (pa_context_connect(priv->context, host, 0, NULL) < 0)
goto fail;
- pa_threaded_mainloop_lock(mainloop);
+ pa_threaded_mainloop_lock(priv->mainloop);
- if (pa_threaded_mainloop_start(mainloop) < 0)
+ if (pa_threaded_mainloop_start(priv->mainloop) < 0)
goto unlock_and_fail;
/* Wait until the context is ready */
- pa_threaded_mainloop_wait(mainloop);
+ pa_threaded_mainloop_wait(priv->mainloop);
- if (pa_context_get_state(context) != PA_CONTEXT_READY)
+ if (pa_context_get_state(priv->context) != PA_CONTEXT_READY)
goto unlock_and_fail;
- if (!(stream = pa_stream_new(context, "audio stream", &ss, &map)))
+ if (!(priv->stream = pa_stream_new(priv->context, "audio stream", &ss,
+ &map)))
goto unlock_and_fail;
- pa_stream_set_state_callback(stream, stream_state_cb, NULL);
- pa_stream_set_write_callback(stream, stream_request_cb, NULL);
- pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);
-
- if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0)
+ pa_stream_set_state_callback(priv->stream, stream_state_cb, ao);
+ pa_stream_set_write_callback(priv->stream, stream_request_cb, ao);
+ pa_stream_set_latency_update_callback(priv->stream,
+ stream_latency_update_cb, ao);
+ pa_buffer_attr bufattr = {
+ .maxlength = -1,
+ .tlength = pa_usec_to_bytes(1000000, &ss),
+ .prebuf = -1,
+ .minreq = -1,
+ .fragsize = -1,
+ };
+ if (pa_stream_connect_playback(priv->stream, sink, &bufattr,
+ PA_STREAM_INTERPOLATE_TIMING
+ | PA_STREAM_AUTO_TIMING_UPDATE, NULL,
+ NULL) < 0)
goto unlock_and_fail;
/* Wait until the stream is ready */
- pa_threaded_mainloop_wait(mainloop);
+ pa_threaded_mainloop_wait(priv->mainloop);
- if (pa_stream_get_state(stream) != PA_STREAM_READY)
+ if (pa_stream_get_state(priv->stream) != PA_STREAM_READY)
goto unlock_and_fail;
- pa_threaded_mainloop_unlock(mainloop);
+ pa_threaded_mainloop_unlock(priv->mainloop);
free(devarg);
- return 1;
+ return 0;
unlock_and_fail:
- if (mainloop)
- pa_threaded_mainloop_unlock(mainloop);
+ if (priv->mainloop)
+ pa_threaded_mainloop_unlock(priv->mainloop);
fail:
- if (context)
- GENERIC_ERR_MSG(context, "Init failed");
+ if (priv->context)
+ GENERIC_ERR_MSG(priv->context, "Init failed");
free(devarg);
- uninit(1);
- return 0;
+ uninit(ao, true);
+ return -1;
}
-/** Destroy libao driver */
-static void uninit(int immed) {
- if (stream && !immed) {
- pa_threaded_mainloop_lock(mainloop);
- waitop(pa_stream_drain(stream, success_cb, NULL));
- }
-
- if (mainloop)
- pa_threaded_mainloop_stop(mainloop);
-
- if (stream) {
- pa_stream_disconnect(stream);
- pa_stream_unref(stream);
- stream = NULL;
- }
-
- if (context) {
- pa_context_disconnect(context);
- pa_context_unref(context);
- context = NULL;
- }
-
- if (mainloop) {
- pa_threaded_mainloop_free(mainloop);
- mainloop = NULL;
- }
+static void cork(struct ao *ao, bool pause)
+{
+ struct priv *priv = ao->priv;
+ pa_threaded_mainloop_lock(priv->mainloop);
+ priv->retval = 0;
+ if (!waitop(priv, pa_stream_cork(priv->stream, pause, success_cb, ao)) ||
+ !priv->retval)
+ GENERIC_ERR_MSG(priv->context, "pa_stream_cork() failed");
}
-/** Play the specified data to the pulseaudio server */
-static int play(void* data, int len, int flags) {
- pa_threaded_mainloop_lock(mainloop);
- if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
- GENERIC_ERR_MSG(context, "pa_stream_write() failed");
+// Play the specified data to the pulseaudio server
+static int play(struct ao *ao, void *data, int len, int flags)
+{
+ struct priv *priv = ao->priv;
+ /* For some reason Pulseaudio behaves worse if this is done after
+ * the write - rapidly repeated seeks result in bogus increasing
+ * reported latency. */
+ if (priv->did_reset)
+ cork(ao, false);
+ pa_threaded_mainloop_lock(priv->mainloop);
+ if (pa_stream_write(priv->stream, data, len, NULL, 0,
+ PA_SEEK_RELATIVE) < 0) {
+ GENERIC_ERR_MSG(priv->context, "pa_stream_write() failed");
len = -1;
}
- pa_threaded_mainloop_unlock(mainloop);
+ if (priv->did_reset) {
+ priv->did_reset = false;
+ if (!waitop(priv, pa_stream_update_timing_info(priv->stream,
+ success_cb, ao))
+ || !priv->retval)
+ GENERIC_ERR_MSG(priv->context, "pa_stream_UPP() failed");
+ } else
+ pa_threaded_mainloop_unlock(priv->mainloop);
return len;
}
-static void cork(int b) {
- int success = 0;
- pa_threaded_mainloop_lock(mainloop);
- if (!waitop(pa_stream_cork(stream, b, success_cb, &success)) ||
- !success)
- GENERIC_ERR_MSG(context, "pa_stream_cork() failed");
+// Reset the audio stream, i.e. flush the playback buffer on the server side
+static void reset(struct ao *ao)
+{
+ // pa_stream_flush() works badly if not corked
+ cork(ao, true);
+ struct priv *priv = ao->priv;
+ pa_threaded_mainloop_lock(priv->mainloop);
+ priv->retval = 0;
+ if (!waitop(priv, pa_stream_flush(priv->stream, success_cb, ao)) ||
+ !priv->retval)
+ GENERIC_ERR_MSG(priv->context, "pa_stream_flush() failed");
+ priv->did_reset = true;
}
-/** Pause the audio stream by corking it on the server */
-static void audio_pause(void) {
- cork(1);
+// Pause the audio stream by corking it on the server
+static void pause(struct ao *ao)
+{
+ cork(ao, true);
}
-/** Resume the audio stream by uncorking it on the server */
-static void audio_resume(void) {
- // without this, certain versions will cause an infinite hang because
- // pa_stream_writable_size returns 0 always.
- // Note that this workaround causes A-V desync after pause
- if (broken_pause) reset();
- cork(0);
-}
-
-/** Reset the audio stream, i.e. flush the playback buffer on the server side */
-static void reset(void) {
- int success = 0;
- pa_threaded_mainloop_lock(mainloop);
- if (!waitop(pa_stream_flush(stream, success_cb, &success)) ||
- !success)
- GENERIC_ERR_MSG(context, "pa_stream_flush() failed");
+// Resume the audio stream by uncorking it on the server
+static void resume(struct ao *ao)
+{
+ struct priv *priv = ao->priv;
+ if (priv->did_reset)
+ return;
+ /* Without this, certain versions will cause an infinite hang because
+ * pa_stream_writable_size returns 0 always.
+ * Note that this workaround causes A-V desync after pause. */
+ if (priv->broken_pause)
+ reset(ao);
+ cork(ao, false);
}
-/** Return number of bytes that may be written to the server without blocking */
-static int get_space(void) {
- size_t l;
- pa_threaded_mainloop_lock(mainloop);
- l = pa_stream_writable_size(stream);
- pa_threaded_mainloop_unlock(mainloop);
- return l;
+// Return number of bytes that may be written to the server without blocking
+static int get_space(struct ao *ao)
+{
+ struct priv *priv = ao->priv;
+ pa_threaded_mainloop_lock(priv->mainloop);
+ size_t space = pa_stream_writable_size(priv->stream);
+ pa_threaded_mainloop_unlock(priv->mainloop);
+ return space;
}
-/** Return the current latency in seconds */
-static float get_delay(void) {
+// Return the current latency in seconds
+static float get_delay(struct ao *ao)
+{
+ struct priv *priv = ao->priv;
pa_usec_t latency = (pa_usec_t) -1;
- pa_threaded_mainloop_lock(mainloop);
- while (pa_stream_get_latency(stream, &latency, NULL) < 0) {
- if (pa_context_errno(context) != PA_ERR_NODATA) {
- GENERIC_ERR_MSG(context, "pa_stream_get_latency() failed");
+ pa_threaded_mainloop_lock(priv->mainloop);
+ while (pa_stream_get_latency(priv->stream, &latency, NULL) < 0) {
+ if (pa_context_errno(priv->context) != PA_ERR_NODATA) {
+ GENERIC_ERR_MSG(priv->context, "pa_stream_get_latency() failed");
break;
}
/* Wait until latency data is available again */
- pa_threaded_mainloop_wait(mainloop);
+ pa_threaded_mainloop_wait(priv->mainloop);
}
- pa_threaded_mainloop_unlock(mainloop);
+ pa_threaded_mainloop_unlock(priv->mainloop);
return latency == (pa_usec_t) -1 ? 0 : latency / 1000000.0;
}
-/** A callback function that is called when the
- * pa_context_get_sink_input_info() operation completes. */
-static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
- struct pa_sink_input_info *pi = userdata;
+/* A callback function that is called when the
+ * pa_context_get_sink_input_info() operation completes. Saves the
+ * volume field of the specified structure to the global variable volume.
+ */
+static void info_func(struct pa_context *c, const struct pa_sink_input_info *i,
+ int is_last, void *userdata)
+{
+ struct ao *ao = userdata;
+ struct priv *priv = ao->priv;
if (is_last < 0) {
- GENERIC_ERR_MSG(context, "Failed to get sink input info");
+ GENERIC_ERR_MSG(priv->context, "Failed to get sink input info");
return;
}
if (!i)
return;
- *pi = *i;
- pa_threaded_mainloop_signal(mainloop, 0);
+ priv->pi = *i;
+ pa_threaded_mainloop_signal(priv->mainloop, 0);
}
-static int control(int cmd, void *arg) {
+static int control(struct ao *ao, int cmd, void *arg)
+{
+ struct priv *priv = ao->priv;
switch (cmd) {
- case AOCONTROL_GET_MUTE: // fallthrough
- case AOCONTROL_GET_VOLUME: {
- struct pa_sink_input_info pi;
- ao_control_vol_t *vol = arg;
- uint32_t devidx = pa_stream_get_index(stream);
- pa_threaded_mainloop_lock(mainloop);
- if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, &pi))) {
- GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed");
- return CONTROL_ERROR;
- }
- // Warning: some information in pi might be unaccessible, because
- // we naively copied the struct, without updating pointers etc.
- // Pointers might point to invalid data, accessors might fail.
- if (cmd == AOCONTROL_GET_VOLUME) {
- if (pi.volume.channels != 2)
- vol->left = vol->right = pa_cvolume_avg(&pi.volume)*100/PA_VOLUME_NORM;
- else {
- vol->left = pi.volume.values[0]*100/PA_VOLUME_NORM;
- vol->right = pi.volume.values[1]*100/PA_VOLUME_NORM;
- }
- } else if (cmd == AOCONTROL_GET_MUTE) {
- vol->left = vol->right = pi.mute ? 0.0f : 1.0f;
+ case AOCONTROL_GET_MUTE: // fallthrough
+ case AOCONTROL_GET_VOLUME: {
+ ao_control_vol_t *vol = arg;
+ uint32_t devidx = pa_stream_get_index(priv->stream);
+ pa_threaded_mainloop_lock(priv->mainloop);
+ if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx,
+ info_func, ao)))
+ {
+ GENERIC_ERR_MSG(priv->context,
+ "pa_stream_get_sink_input_info() failed");
+ return CONTROL_ERROR;
+ }
+ // Warning: some information in pi might be unaccessible, because
+ // we naively copied the struct, without updating pointers etc.
+ // Pointers might point to invalid data, accessors might fail.
+ if (cmd == AOCONTROL_GET_VOLUME) {
+ if (priv->pi.volume.channels != 2)
+ vol->left = vol->right =
+ pa_cvolume_avg(&priv->pi.volume) * 100 / PA_VOLUME_NORM;
+ else {
+ vol->left = priv->pi.volume.values[0] * 100 / PA_VOLUME_NORM;
+ vol->right = priv->pi.volume.values[1] * 100 / PA_VOLUME_NORM;
}
+ } else if (cmd == AOCONTROL_GET_MUTE) {
+ vol->left = vol->right = priv->pi.mute ? 0.0f : 1.0f;
+ }
- return CONTROL_OK;
+ return CONTROL_OK;
}
- case AOCONTROL_SET_MUTE: // fallthrough
- case AOCONTROL_SET_VOLUME: {
- const ao_control_vol_t *vol = arg;
- pa_operation *o;
- struct pa_cvolume volume;
+ case AOCONTROL_SET_MUTE: // fallthrough
+ case AOCONTROL_SET_VOLUME: {
+ const ao_control_vol_t *vol = arg;
+ pa_operation *o;
+ struct pa_cvolume volume;
+
+ pa_cvolume_reset(&volume, ao->channels);
+ if (volume.channels != 2)
+ pa_cvolume_set(&volume, volume.channels,
+ (pa_volume_t)vol->left * PA_VOLUME_NORM / 100);
+ else {
+ volume.values[0] = (pa_volume_t)vol->left * PA_VOLUME_NORM / 100;
+ volume.values[1] = (pa_volume_t)vol->right * PA_VOLUME_NORM / 100;
+ }
- pa_cvolume_reset(&volume, ao_data.channels);
- if (volume.channels != 2)
- pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100);
- else {
- volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100;
- volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100;
+ pa_threaded_mainloop_lock(priv->mainloop);
+ uint32_t stream_index = pa_stream_get_index(priv->stream);
+ if (cmd == AOCONTROL_SET_VOLUME) {
+ o = pa_context_set_sink_input_volume(priv->context, stream_index,
+ &volume, NULL, NULL);
+ if (!o) {
+ pa_threaded_mainloop_unlock(priv->mainloop);
+ GENERIC_ERR_MSG(priv->context,
+ "pa_context_set_sink_input_volume() failed");
+ return CONTROL_ERROR;
}
-
- pa_threaded_mainloop_lock(mainloop);
- if (cmd == AOCONTROL_SET_VOLUME) {
- o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL);
- if (!o) {
- pa_threaded_mainloop_unlock(mainloop);
- GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed");
- return CONTROL_ERROR;
- }
- } else if (cmd == AOCONTROL_SET_MUTE) {
- int mute = vol->left == 0.0f || vol->right == 0.0f;
- o = pa_context_set_sink_input_mute(context, pa_stream_get_index(stream), mute, NULL, NULL);
- if (!o) {
- pa_threaded_mainloop_unlock(mainloop);
- GENERIC_ERR_MSG(context, "pa_context_set_sink_input_mute() failed");
- return CONTROL_ERROR;
- }
- } else
- abort();
- /* We don't wait for completion here */
- pa_operation_unref(o);
- pa_threaded_mainloop_unlock(mainloop);
- return CONTROL_OK;
+ } else if (cmd == AOCONTROL_SET_MUTE) {
+ int mute = vol->left == 0.0f || vol->right == 0.0f;
+ o = pa_context_set_sink_input_mute(priv->context, stream_index,
+ mute, NULL, NULL);
+ if (!o) {
+ pa_threaded_mainloop_unlock(priv->mainloop);
+ GENERIC_ERR_MSG(priv->context,
+ "pa_context_set_sink_input_mute() failed");
+ return CONTROL_ERROR;
+ }
+ } else
+ abort();
+ /* We don't wait for completion here */
+ pa_operation_unref(o);
+ pa_threaded_mainloop_unlock(priv->mainloop);
+ return CONTROL_OK;
}
- default:
- return CONTROL_UNKNOWN;
+ default:
+ return CONTROL_UNKNOWN;
}
}
+
+const struct ao_driver audio_out_pulse = {
+ .is_new = true,
+ .info = &(const struct ao_info) {
+ "PulseAudio audio output",
+ "pulse",
+ "Lennart Poettering",
+ "",
+ },
+ .control = control,
+ .init = init,
+ .uninit = uninit,
+ .reset = reset,
+ .get_space = get_space,
+ .play = play,
+ .get_delay = get_delay,
+ .pause = pause,
+ .resume = resume,
+};
diff --git a/libao2/audio_out.c b/libao2/audio_out.c
index a91a0d6d72..6130e2ed33 100644
--- a/libao2/audio_out.c
+++ b/libao2/audio_out.c
@@ -136,10 +136,11 @@ void list_audio_out(void)
mp_msg(MSGT_GLOBAL, MSGL_INFO,"\n");
}
-struct ao *ao_create(void)
+struct ao *ao_create(struct MPOpts *opts, struct input_ctx *input)
{
struct ao *r = talloc(NULL, struct ao);
- *r = (struct ao){.outburst = OUTBURST, .buffersize = -1};
+ *r = (struct ao){.outburst = OUTBURST, .buffersize = -1,
+ .opts = opts, .input_ctx = input };
return r;
}
diff --git a/libao2/audio_out.h b/libao2/audio_out.h
index c5ddb5bf60..aafedbf178 100644
--- a/libao2/audio_out.h
+++ b/libao2/audio_out.h
@@ -81,6 +81,8 @@ struct ao {
bool no_persistent_volume;
const struct ao_driver *driver;
void *priv;
+ struct MPOpts *opts;
+ struct input_ctx *input_ctx;
};
extern char *ao_subdevice;
@@ -118,7 +120,7 @@ typedef struct ao_control_vol {
float right;
} ao_control_vol_t;
-struct ao *ao_create(void);
+struct ao *ao_create(struct MPOpts *opts, struct input_ctx *input);
void ao_init(struct ao *ao, char **ao_list);
void ao_uninit(struct ao *ao, bool cut_audio);
int ao_play(struct ao *ao, void *data, int len, int flags);
diff --git a/libao2/audio_out_internal.h b/libao2/audio_out_internal.h
index 67bcfa953d..215428fb0e 100644
--- a/libao2/audio_out_internal.h
+++ b/libao2/audio_out_internal.h
@@ -19,6 +19,8 @@
#ifndef MPLAYER_AUDIO_OUT_INTERNAL_H
#define MPLAYER_AUDIO_OUT_INTERNAL_H
+#include "options.h"
+
// prototypes:
//static ao_info_t info;
static int control(int cmd, void *arg);
@@ -33,6 +35,8 @@ static void audio_resume(void);
extern struct ao *global_ao;
#define ao_data (*global_ao)
+#define mixer_channel (global_ao->opts->mixer_channel)
+#define mixer_device (global_ao->opts->mixer_device)
#define LIBAO_EXTERN(x) const struct ao_driver audio_out_##x = { \
.info = &info, \
diff --git a/libmpcodecs/img_format.c b/libmpcodecs/img_format.c
index 54ccc42b2a..033c0a4e3e 100644
--- a/libmpcodecs/img_format.c
+++ b/libmpcodecs/img_format.c
@@ -103,9 +103,6 @@ const char *vo_format_name(int format)
case IMGFMT_YUVP: return "Packed YUVP";
case IMGFMT_UYVP: return "Packed UYVP";
case IMGFMT_MPEGPES: return "Mpeg PES";
- case IMGFMT_ZRMJPEGNI: return "Zoran MJPEG non-interlaced";
- case IMGFMT_ZRMJPEGIT: return "Zoran MJPEG top field first";
- case IMGFMT_ZRMJPEGIB: return "Zoran MJPEG bottom field first";
case IMGFMT_XVMC_MOCO_MPEG2: return "MPEG1/2 Motion Compensation";
case IMGFMT_XVMC_IDCT_MPEG2: return "MPEG1/2 Motion Compensation and IDCT";
case IMGFMT_VDPAU_MPEG1: return "MPEG1 VDPAU acceleration";
diff --git a/libmpcodecs/img_format.h b/libmpcodecs/img_format.h
index a3a475a68b..4200282f98 100644
--- a/libmpcodecs/img_format.h
+++ b/libmpcodecs/img_format.h
@@ -192,11 +192,6 @@
/* Compressed Formats */
#define IMGFMT_MPEGPES (('M'<<24)|('P'<<16)|('E'<<8)|('S'))
#define IMGFMT_MJPEG (('M')|('J'<<8)|('P'<<16)|('G'<<24))
-/* Formats that are understood by zoran chips, we include
- * non-interlaced, interlaced top-first, interlaced bottom-first */
-#define IMGFMT_ZRMJPEGNI (('Z'<<24)|('R'<<16)|('N'<<8)|('I'))
-#define IMGFMT_ZRMJPEGIT (('Z'<<24)|('R'<<16)|('I'<<8)|('T'))
-#define IMGFMT_ZRMJPEGIB (('Z'<<24)|('R'<<16)|('I'<<8)|('B'))
// I think that this code could not be used by any other codec/format
#define IMGFMT_XVMC 0x1DC70000
diff --git a/libmpcodecs/mp_image.c b/libmpcodecs/mp_image.c
index 8cdb5eee6b..4e20dee119 100644
--- a/libmpcodecs/mp_image.c
+++ b/libmpcodecs/mp_image.c
@@ -99,9 +99,7 @@ void mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt){
mpi->flags&=~(MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV|MP_IMGFLAG_SWAPPED);
mpi->imgfmt=out_fmt;
// compressed formats
- if(out_fmt == IMGFMT_MPEGPES ||
- out_fmt == IMGFMT_ZRMJPEGNI || out_fmt == IMGFMT_ZRMJPEGIT || out_fmt == IMGFMT_ZRMJPEGIB ||
- IMGFMT_IS_HWACCEL(out_fmt)){
+ if(out_fmt == IMGFMT_MPEGPES || IMGFMT_IS_HWACCEL(out_fmt)){
mpi->bpp=0;
return;
}
diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c
index ce80caa74b..4dcddb1d08 100644
--- a/libmpcodecs/vf_ass.c
+++ b/libmpcodecs/vf_ass.c
@@ -370,7 +370,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
mp_ass_reload_options(vf->priv->renderer, vf->opts);
osd->ass_force_reload = false;
images = ass_render_frame(vf->priv->renderer, osd->ass_track,
- (pts + sub_delay) * 1000 + .5, NULL);
+ (pts - osd->sub_offset + sub_delay) * 1000 + .5, NULL);
}
prepare_image(vf, mpi);
diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c
index b7c16a7759..a6bd165dee 100644
--- a/libmpcodecs/vf_vo.c
+++ b/libmpcodecs/vf_vo.c
@@ -33,8 +33,6 @@
#include "sub/ass_mp.h"
#include "sub/sub.h"
-//===========================================================================//
-
extern float sub_delay;
struct vf_priv_s {
@@ -47,45 +45,47 @@ struct vf_priv_s {
};
#define video_out (vf->priv->vo)
-static int query_format(struct vf_instance *vf, unsigned int fmt); /* forward declaration */
-static void draw_slice(struct vf_instance *vf, unsigned char** src, int* stride, int w,int h, int x, int y);
+static int query_format(struct vf_instance *vf, unsigned int fmt);
+static void draw_slice(struct vf_instance *vf, unsigned char **src,
+ int *stride, int w, int h, int x, int y);
static int config(struct vf_instance *vf,
- int width, int height, int d_width, int d_height,
- unsigned int flags, unsigned int outfmt){
+ int width, int height, int d_width, int d_height,
+ unsigned int flags, unsigned int outfmt)
+{
- if ((width <= 0) || (height <= 0) || (d_width <= 0) || (d_height <= 0))
- {
- mp_msg(MSGT_CPLAYER, MSGL_ERR, "VO: invalid dimensions!\n");
- return 0;
+ if ((width <= 0) || (height <= 0) || (d_width <= 0) || (d_height <= 0)) {
+ mp_msg(MSGT_CPLAYER, MSGL_ERR, "VO: invalid dimensions!\n");
+ return 0;
}
const vo_info_t *info = video_out->driver->info;
- mp_msg(MSGT_CPLAYER,MSGL_INFO,"VO: [%s] %dx%d => %dx%d %s %s%s%s%s\n",info->short_name,
- width, height,
- d_width, d_height,
- vo_format_name(outfmt),
- (flags&VOFLAG_FULLSCREEN)?" [fs]":"",
- (flags&VOFLAG_MODESWITCHING)?" [vm]":"",
- (flags&VOFLAG_SWSCALE)?" [zoom]":"",
- (flags&VOFLAG_FLIPPING)?" [flip]":"");
- mp_msg(MSGT_CPLAYER,MSGL_V,"VO: Description: %s\n",info->name);
- mp_msg(MSGT_CPLAYER,MSGL_V,"VO: Author: %s\n", info->author);
- if(info->comment && strlen(info->comment) > 0)
- mp_msg(MSGT_CPLAYER,MSGL_V,"VO: Comment: %s\n", info->comment);
+ mp_msg(MSGT_CPLAYER, MSGL_INFO, "VO: [%s] %dx%d => %dx%d %s %s%s%s%s\n",
+ info->short_name,
+ width, height,
+ d_width, d_height,
+ vo_format_name(outfmt),
+ (flags & VOFLAG_FULLSCREEN) ? " [fs]" : "",
+ (flags & VOFLAG_MODESWITCHING) ? " [vm]" : "",
+ (flags & VOFLAG_SWSCALE) ? " [zoom]" : "",
+ (flags & VOFLAG_FLIPPING) ? " [flip]" : "");
+ mp_msg(MSGT_CPLAYER, MSGL_V, "VO: Description: %s\n", info->name);
+ mp_msg(MSGT_CPLAYER, MSGL_V, "VO: Author: %s\n", info->author);
+ if (info->comment && strlen(info->comment) > 0)
+ mp_msg(MSGT_CPLAYER, MSGL_V, "VO: Comment: %s\n", info->comment);
// save vo's stride capability for the wanted colorspace:
- vf->default_caps=query_format(vf,outfmt);
+ vf->default_caps = query_format(vf, outfmt);
vf->draw_slice = (vf->default_caps & VOCAP_NOSLICES) ? NULL : draw_slice;
if (vo_config(video_out, width, height, d_width, d_height, flags, outfmt))
- return 0;
+ return 0;
#ifdef CONFIG_ASS
vf->priv->scale_ratio = (double) d_width / d_height * height / width;
if (vf->priv->renderer) {
- mp_ass_configure(vf->priv->renderer, vf->opts, width, height,
+ mp_ass_configure(vf->priv->renderer, vf->opts, width, height,
vf->default_caps & VFCAP_EOSD_UNSCALED);
}
@@ -96,40 +96,43 @@ static int config(struct vf_instance *vf,
return 1;
}
-static int control(struct vf_instance *vf, int request, void* data)
+static int control(struct vf_instance *vf, int request, void *data)
{
- switch(request){
+ switch (request) {
case VFCTRL_GET_DEINTERLACE:
- {
- if(!video_out) return CONTROL_FALSE; // vo not configured?
+ if (!video_out)
+ return CONTROL_FALSE; // vo not configured?
return vo_control(video_out, VOCTRL_GET_DEINTERLACE, data) == VO_TRUE;
- }
case VFCTRL_SET_DEINTERLACE:
- {
- if(!video_out) return CONTROL_FALSE; // vo not configured?
+ if (!video_out)
+ return CONTROL_FALSE; // vo not configured?
return vo_control(video_out, VOCTRL_SET_DEINTERLACE, data) == VO_TRUE;
- }
case VFCTRL_GET_YUV_COLORSPACE:
return vo_control(video_out, VOCTRL_GET_YUV_COLORSPACE, data) == true;
case VFCTRL_SET_YUV_COLORSPACE:
return vo_control(video_out, VOCTRL_SET_YUV_COLORSPACE, data) == true;
case VFCTRL_DRAW_OSD:
- if(!video_out->config_ok) return CONTROL_FALSE; // vo not configured?
- vo_draw_osd(video_out, data);
- return CONTROL_TRUE;
- case VFCTRL_SET_EQUALIZER:
- {
- vf_equalizer_t *eq=data;
- if(!video_out->config_ok) return CONTROL_FALSE; // vo not configured?
- struct voctrl_set_equalizer_args param = {eq->item, eq->value};
- return vo_control(video_out, VOCTRL_SET_EQUALIZER, &param) == VO_TRUE;
+ if (!video_out->config_ok)
+ return CONTROL_FALSE; // vo not configured?
+ vo_draw_osd(video_out, data);
+ return CONTROL_TRUE;
+ case VFCTRL_SET_EQUALIZER: {
+ vf_equalizer_t *eq = data;
+ if (!video_out->config_ok)
+ return CONTROL_FALSE; // vo not configured?
+ struct voctrl_set_equalizer_args param = {
+ eq->item, eq->value
+ };
+ return vo_control(video_out, VOCTRL_SET_EQUALIZER, &param) == VO_TRUE;
}
- case VFCTRL_GET_EQUALIZER:
- {
- vf_equalizer_t *eq=data;
- if(!video_out->config_ok) return CONTROL_FALSE; // vo not configured?
- struct voctrl_get_equalizer_args param = {eq->item, &eq->value};
- return vo_control(video_out, VOCTRL_GET_EQUALIZER, &param) == VO_TRUE;
+ case VFCTRL_GET_EQUALIZER: {
+ vf_equalizer_t *eq = data;
+ if (!video_out->config_ok)
+ return CONTROL_FALSE; // vo not configured?
+ struct voctrl_get_equalizer_args param = {
+ eq->item, &eq->value
+ };
+ return vo_control(video_out, VOCTRL_GET_EQUALIZER, &param) == VO_TRUE;
}
#ifdef CONFIG_ASS
case VFCTRL_INIT_EOSD:
@@ -141,8 +144,7 @@ static int control(struct vf_instance *vf, int request, void* data)
vf->priv->prev_visibility = false;
return CONTROL_TRUE;
}
- case VFCTRL_DRAW_EOSD:
- {
+ case VFCTRL_DRAW_EOSD: {
struct osd_state *osd = data;
mp_eosd_images_t images = {NULL, 2};
ASS_Renderer *renderer = vf->priv->renderer;
@@ -158,7 +160,7 @@ static int control(struct vf_instance *vf, int request, void* data)
vf->priv->prev_visibility = false;
osd->ass_track_changed = false;
if (sub_visibility && osd->ass_track && (osd->pts != MP_NOPTS_VALUE)) {
- struct mp_eosd_res res = {0};
+ struct mp_eosd_res res = { 0 };
if (vo_control(video_out, VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) {
ass_set_frame_size(renderer, res.w, res.h);
ass_set_margins(renderer, res.mt, res.mb, res.ml, res.mr);
@@ -168,7 +170,7 @@ static int control(struct vf_instance *vf, int request, void* data)
if (osd->ass_force_reload)
mp_ass_reload_options(vf->priv->renderer, vf->opts);
images.imgs = ass_render_frame(renderer, osd->ass_track,
- (osd->pts+sub_delay) * 1000 + .5,
+ (osd->pts + sub_delay) * 1000 + .5,
&images.changed);
if (!vf->priv->prev_visibility || osd->ass_force_reload)
images.changed = 2;
@@ -183,53 +185,58 @@ static int control(struct vf_instance *vf, int request, void* data)
return CONTROL_UNKNOWN;
}
-static int query_format(struct vf_instance *vf, unsigned int fmt){
+static int query_format(struct vf_instance *vf, unsigned int fmt)
+{
int flags = vo_control(video_out, VOCTRL_QUERY_FORMAT, &fmt);
// draw_slice() accepts stride, draw_frame() doesn't:
- if(flags)
- if(fmt==IMGFMT_YV12 || fmt==IMGFMT_I420 || fmt==IMGFMT_IYUV)
- flags|=VFCAP_ACCEPT_STRIDE;
+ if (flags)
+ if (fmt == IMGFMT_YV12 || fmt == IMGFMT_I420 || fmt == IMGFMT_IYUV)
+ flags |= VFCAP_ACCEPT_STRIDE;
return flags;
}
static void get_image(struct vf_instance *vf,
- mp_image_t *mpi){
+ mp_image_t *mpi)
+{
if (!video_out->config_ok)
return;
// GET_IMAGE is required for hardware-accelerated formats
- if(vo_directrendering ||
- IMGFMT_IS_HWACCEL(mpi->imgfmt))
- vo_control(video_out, VOCTRL_GET_IMAGE, mpi);
+ if (vo_directrendering || IMGFMT_IS_HWACCEL(mpi->imgfmt))
+ vo_control(video_out, VOCTRL_GET_IMAGE, mpi);
}
-static int put_image(struct vf_instance *vf,
- mp_image_t *mpi, double pts){
- if(!video_out->config_ok) return 0; // vo not configured?
- // first check, maybe the vo/vf plugin implements draw_image using mpi:
- if (vo_draw_image(video_out, mpi, pts) >= 0)
- return 1;
- // nope, fallback to old draw_frame/draw_slice:
- if(!(mpi->flags&(MP_IMGFLAG_DIRECT|MP_IMGFLAG_DRAW_CALLBACK))){
- // blit frame:
-// if(mpi->flags&MP_IMGFLAG_PLANAR)
- if(vf->default_caps&VFCAP_ACCEPT_STRIDE)
- vo_draw_slice(video_out, mpi->planes,mpi->stride,mpi->w,mpi->h,0,0);
- else
- vo_draw_frame(video_out, mpi->planes);
- }
- return 1;
+static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
+{
+ if (!video_out->config_ok)
+ return 0;
+ // first check, maybe the vo/vf plugin implements draw_image using mpi:
+ if (vo_draw_image(video_out, mpi, pts) >= 0)
+ return 1;
+ // nope, fallback to old draw_frame/draw_slice:
+ if (!(mpi->flags & (MP_IMGFLAG_DIRECT | MP_IMGFLAG_DRAW_CALLBACK))) {
+ // blit frame:
+ if (vf->default_caps & VFCAP_ACCEPT_STRIDE)
+ vo_draw_slice(video_out, mpi->planes, mpi->stride, mpi->w, mpi->h,
+ 0, 0);
+ else
+ vo_draw_frame(video_out, mpi->planes);
+ }
+ return 1;
}
-static void start_slice(struct vf_instance *vf,
- mp_image_t *mpi) {
- if(!video_out->config_ok) return; // vo not configured?
- vo_control(video_out, VOCTRL_START_SLICE,mpi);
+static void start_slice(struct vf_instance *vf, mp_image_t *mpi)
+{
+ if (!video_out->config_ok)
+ return;
+ vo_control(video_out, VOCTRL_START_SLICE, mpi);
}
-static void draw_slice(struct vf_instance *vf,
- unsigned char** src, int* stride, int w,int h, int x, int y){
- if(!video_out->config_ok) return; // vo not configured?
- vo_draw_slice(video_out, src,stride,w,h,x,y);
+static void draw_slice(struct vf_instance *vf, unsigned char **src,
+ int *stride, int w, int h, int x, int y)
+{
+ if (!video_out->config_ok)
+ return;
+ vo_draw_slice(video_out, src, stride, w, h, x, y);
}
static void uninit(struct vf_instance *vf)
@@ -245,20 +252,21 @@ static void uninit(struct vf_instance *vf)
free(vf->priv);
}
}
-//===========================================================================//
-static int vf_open(vf_instance_t *vf, char *args){
- vf->config=config;
- vf->control=control;
- vf->query_format=query_format;
- vf->get_image=get_image;
- vf->put_image=put_image;
- vf->draw_slice=draw_slice;
- vf->start_slice=start_slice;
- vf->uninit=uninit;
- vf->priv=calloc(1, sizeof(struct vf_priv_s));
+static int vf_open(vf_instance_t *vf, char *args)
+{
+ vf->config = config;
+ vf->control = control;
+ vf->query_format = query_format;
+ vf->get_image = get_image;
+ vf->put_image = put_image;
+ vf->draw_slice = draw_slice;
+ vf->start_slice = start_slice;
+ vf->uninit = uninit;
+ vf->priv = calloc(1, sizeof(struct vf_priv_s));
vf->priv->vo = (struct vo *)args;
- if(!video_out) return 0; // no vo ?
+ if (!video_out)
+ return 0;
return 1;
}
@@ -270,5 +278,3 @@ const vf_info_t vf_info_vo = {
vf_open,
NULL
};
-
-//===========================================================================//
diff --git a/libmpdemux/demux_lavf.c b/libmpdemux/demux_lavf.c
index 5fb66adb9d..f8311e215c 100644
--- a/libmpdemux/demux_lavf.c
+++ b/libmpdemux/demux_lavf.c
@@ -517,7 +517,7 @@ static void handle_stream(demuxer_t *demuxer, AVFormatContext *avfc, int i)
AVCodec *avc = avcodec_find_decoder(codec->codec_id);
const char *codec_name = avc ? avc->name : "unknown";
if (!avc && *stream_type == 's' && demuxer->s_streams[i])
- codec_name = sh_sub_type2str(((sh_sub_t *)demuxer->s_streams[i])->type);
+ codec_name = sh_sub_type2str((demuxer->s_streams[i])->type);
mp_msg(MSGT_DEMUX, MSGL_INFO, "[lavf] stream %d: %s (%s), -%cid %d",
i, stream_type, codec_name, *stream_type, stream_id);
if (lang && lang->value && *stream_type != 'v')
diff --git a/libvo/cocoa_common.h b/libvo/cocoa_common.h
index 1330caacc5..d47ac51500 100644
--- a/libvo/cocoa_common.h
+++ b/libvo/cocoa_common.h
@@ -1,3 +1,22 @@
+/*
+ * Cocoa OpenGL Backend
+ *
+ * This file is part of mplayer2.
+ *
+ * mplayer2 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mplayer2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mplayer2. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#ifndef MPLAYER_COCOA_COMMON_H
#define MPLAYER_COCOA_COMMON_H
@@ -16,6 +35,7 @@ int vo_cocoa_create_window(struct vo *vo, uint32_t d_width,
void vo_cocoa_swap_buffers(void);
int vo_cocoa_check_events(struct vo *vo);
void vo_cocoa_fullscreen(struct vo *vo);
+void vo_cocoa_ontop(struct vo *vo);
// returns an int to conform to the gl extensions from other platforms
int vo_cocoa_swap_interval(int enabled);
diff --git a/libvo/cocoa_common.m b/libvo/cocoa_common.m
index 4eccf1a320..e8ef278b1e 100644
--- a/libvo/cocoa_common.m
+++ b/libvo/cocoa_common.m
@@ -1,3 +1,22 @@
+/*
+ * Cocoa OpenGL Backend
+ *
+ * This file is part of mplayer2.
+ *
+ * mplayer2 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mplayer2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mplayer2. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#import <Cocoa/Cocoa.h>
#import <OpenGL/OpenGL.h>
#import <QuartzCore/QuartzCore.h>
@@ -62,8 +81,15 @@ struct vo_cocoa_state {
NSString *window_title;
+ NSInteger windowed_window_level;
+ NSInteger fullscreen_window_level;
+
int last_screensaver_update;
+ int display_cursor;
+ int cursor_timer;
+ int cursor_autohide_delay;
+
bool did_resize;
bool out_fs_resize;
};
@@ -74,8 +100,10 @@ struct vo *l_vo;
// local function definitions
struct vo_cocoa_state *vo_cocoa_init_state(void);
+void vo_set_level(int ontop);
void update_screen_info(void);
void resize_window(struct vo *vo);
+void vo_cocoa_display_cursor(int requested_state);
void create_menu(void);
bool is_lion_or_better(void);
@@ -89,8 +117,10 @@ struct vo_cocoa_state *vo_cocoa_init_state(void)
.previous_video_size = {0,0},
.windowed_mask = NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask,
.fullscreen_mask = NSBorderlessWindowMask,
+ .fullscreen_window_level = NSNormalWindowLevel + 1,
.windowed_frame = {{0,0},{0,0}},
.out_fs_resize = NO,
+ .display_cursor = 1,
};
return s;
}
@@ -99,6 +129,7 @@ int vo_cocoa_init(struct vo *vo)
{
s = vo_cocoa_init_state();
s->pool = [[NSAutoreleasePool alloc] init];
+ s->cursor_autohide_delay = vo->opts->cursor_autohide_delay;
NSApplicationLoad();
NSApp = [NSApplication sharedApplication];
[NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
@@ -155,10 +186,30 @@ void resize_window(struct vo *vo)
[s->glContext update];
}
+void vo_set_level(int ontop)
+{
+ if (ontop) {
+ s->windowed_window_level = NSNormalWindowLevel + 1;
+ } else {
+ s->windowed_window_level = NSNormalWindowLevel;
+ }
+
+ if (!vo_fs)
+ [s->window setLevel:s->windowed_window_level];
+}
+
+void vo_cocoa_ontop(struct vo *vo)
+{
+ struct MPOpts *opts = vo->opts;
+ opts->vo_ontop = !opts->vo_ontop;
+ vo_set_level(opts->vo_ontop);
+}
+
int vo_cocoa_create_window(struct vo *vo, uint32_t d_width,
uint32_t d_height, uint32_t flags,
int gl3profile)
{
+ struct MPOpts *opts = vo->opts;
if (s->current_video_size.width > 0 || s->current_video_size.height > 0)
s->previous_video_size = s->current_video_size;
s->current_video_size = NSMakeSize(d_width, d_height);
@@ -207,6 +258,8 @@ int vo_cocoa_create_window(struct vo *vo, uint32_t d_width,
if (flags & VOFLAG_FULLSCREEN)
vo_cocoa_fullscreen(vo);
+
+ vo_set_level(opts->vo_ontop);
} else {
if (s->current_video_size.width != s->previous_video_size.width ||
s->current_video_size.height != s->previous_video_size.height) {
@@ -238,18 +291,42 @@ void vo_cocoa_swap_buffers()
[s->glContext flushBuffer];
}
+void vo_cocoa_display_cursor(int requested_state)
+{
+ if (requested_state) {
+ if (!vo_fs || s->cursor_autohide_delay > -2) {
+ s->display_cursor = requested_state;
+ CGDisplayShowCursor(kCGDirectMainDisplay);
+ }
+ } else {
+ if (s->cursor_autohide_delay != -1) {
+ s->display_cursor = requested_state;
+ CGDisplayHideCursor(kCGDirectMainDisplay);
+ }
+ }
+}
+
int vo_cocoa_check_events(struct vo *vo)
{
+ NSEvent *event;
+ float curTime = TickCount()/60;
+ int msCurTime = (int) (curTime * 1000);
+
+ // automatically hide mouse cursor
+ if (vo_fs && s->display_cursor &&
+ (msCurTime - s->cursor_timer >= s->cursor_autohide_delay)) {
+ vo_cocoa_display_cursor(0);
+ s->cursor_timer = msCurTime;
+ }
+
//update activity every 30 seconds to prevent
//screensaver from starting up.
- int curTime = TickCount()/60;
- if (curTime - s->last_screensaver_update >= 30 || s->last_screensaver_update == 0)
+ if ((int)curTime - s->last_screensaver_update >= 30 || s->last_screensaver_update == 0)
{
UpdateSystemActivity(UsrActivity);
- s->last_screensaver_update = curTime;
+ s->last_screensaver_update = (int)curTime;
}
- NSEvent *event;
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
inMode:NSEventTrackingRunLoopMode dequeue:YES];
if (event == nil)
@@ -333,14 +410,16 @@ bool is_lion_or_better(void)
- (void) fullscreen
{
if (!vo_fs) {
+ update_screen_info();
[NSApp setPresentationOptions:NSApplicationPresentationHideDock|NSApplicationPresentationHideMenuBar];
s->windowed_frame = [self frame];
[self setHasShadow:NO];
[self setStyleMask:s->fullscreen_mask];
[self setFrame:s->screen_frame display:YES animate:NO];
- [self setLevel:NSNormalWindowLevel + 1];
- CGDisplayHideCursor(kCGDirectMainDisplay);
+ [self setLevel:s->fullscreen_window_level];
vo_fs = VO_TRUE;
+ vo_cocoa_display_cursor(0);
+ [self setMovableByWindowBackground: NO];
} else {
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
[self setHasShadow:YES];
@@ -352,9 +431,10 @@ bool is_lion_or_better(void)
s->out_fs_resize = NO;
}
[self setContentAspectRatio:s->current_video_size];
- [self setLevel:NSNormalWindowLevel];
- CGDisplayShowCursor(kCGDirectMainDisplay);
+ [self setLevel:s->windowed_window_level];
vo_fs = VO_FALSE;
+ vo_cocoa_display_cursor(1);
+ [self setMovableByWindowBackground: YES];
}
}
@@ -372,6 +452,12 @@ bool is_lion_or_better(void)
return NO;
}
+- (BOOL) isMovableByWindowBackground
+{
+ // this is only valid as a starting value. it will be rewritten in the -fullscreen method.
+ return !vo_fs;
+}
+
- (void) handleQuitEvent:(NSAppleEventDescriptor*)e withReplyEvent:(NSAppleEventDescriptor*)r
{
mplayer_put_key(l_vo->key_fifo, KEY_CLOSE_WIN);
@@ -400,6 +486,12 @@ bool is_lion_or_better(void)
}
}
+- (void) mouseMoved: (NSEvent *) theEvent
+{
+ if (vo_fs)
+ vo_cocoa_display_cursor(1);
+}
+
- (void) mouseDragged:(NSEvent *)theEvent
{
[self mouseEvent: theEvent];
@@ -445,23 +537,23 @@ bool is_lion_or_better(void)
- (void) mouseEvent:(NSEvent *)theEvent
{
- if ( [theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9 )
- {
+ if ([theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9) {
int buttonNumber = [theEvent buttonNumber];
// Fix to mplayer defined button order: left, middle, right
- if (buttonNumber == 1)
- buttonNumber = 2;
- else if (buttonNumber == 2)
- buttonNumber = 1;
+ if (buttonNumber == 1) buttonNumber = 2;
+ else if (buttonNumber == 2) buttonNumber = 1;
switch ([theEvent type]) {
case NSLeftMouseDown:
- break;
case NSRightMouseDown:
case NSOtherMouseDown:
mplayer_put_key(l_vo->key_fifo, (MOUSE_BTN0 + buttonNumber) | MP_KEY_DOWN);
+ // Looks like Cocoa doesn't create MouseUp events when we are
+ // doing the second click in a double click. Put in the key_fifo
+ // the key that would be put from the MouseUp handling code.
+ if([theEvent clickCount] == 2)
+ mplayer_put_key(l_vo->key_fifo, MOUSE_BTN0 + buttonNumber);
break;
case NSLeftMouseUp:
- break;
case NSRightMouseUp:
case NSOtherMouseUp:
mplayer_put_key(l_vo->key_fifo, MOUSE_BTN0 + buttonNumber);
@@ -473,7 +565,7 @@ bool is_lion_or_better(void)
- (void) applicationWillBecomeActive:(NSNotification *)aNotification
{
if (vo_fs) {
- [s->window setLevel:NSNormalWindowLevel + 1];
+ [s->window setLevel:s->fullscreen_window_level];
[NSApp setPresentationOptions:NSApplicationPresentationHideDock|NSApplicationPresentationHideMenuBar];
[s->window makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps: YES];
@@ -483,7 +575,7 @@ bool is_lion_or_better(void)
- (void) applicationWillResignActive:(NSNotification *)aNotification
{
if (vo_fs) {
- [s->window setLevel:NSNormalWindowLevel];
+ [s->window setLevel:s->windowed_window_level];
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
}
}
diff --git a/libvo/gl_common.c b/libvo/gl_common.c
index c5abc81e15..414e52dbd2 100644
--- a/libvo/gl_common.c
+++ b/libvo/gl_common.c
@@ -2447,6 +2447,7 @@ MPGLContext *init_mpglcontext(enum MPGLType type, struct vo *vo)
ctx->check_events = cocoa_check_events;
ctx->update_xinerama_info = cocoa_update_xinerama_info;
ctx->fullscreen = cocoa_fullscreen;
+ ctx->ontop = vo_cocoa_ontop;
ctx->vo_uninit = vo_cocoa_uninit;
if (vo_cocoa_init(vo))
return ctx;
diff --git a/libvo/video_out.c b/libvo/video_out.c
index 094d5b1a12..540fedb132 100644
--- a/libvo/video_out.c
+++ b/libvo/video_out.c
@@ -118,7 +118,6 @@ extern struct vo_driver video_out_tdfx_vid;
extern struct vo_driver video_out_xvr100;
extern struct vo_driver video_out_tga;
extern struct vo_driver video_out_corevideo;
-extern struct vo_driver video_out_quartz;
extern struct vo_driver video_out_pnm;
extern struct vo_driver video_out_md5sum;
@@ -140,12 +139,12 @@ const struct vo_driver *video_out_drivers[] =
#ifdef CONFIG_KVA
&video_out_kva,
#endif
+#ifdef CONFIG_GL_COCOA
+ &video_out_gl,
+#endif
#ifdef CONFIG_COREVIDEO
&video_out_corevideo,
#endif
-#ifdef CONFIG_QUARTZ
- &video_out_quartz,
-#endif
#ifdef CONFIG_XMGA
&video_out_xmga,
#endif
@@ -183,7 +182,7 @@ const struct vo_driver *video_out_drivers[] =
#ifdef CONFIG_SDL
&video_out_sdl,
#endif
-#ifdef CONFIG_GL
+#if (defined CONFIG_GL && !defined CONFIG_GL_COCOA)
&video_out_gl,
#endif
#ifdef CONFIG_DGA
@@ -378,6 +377,7 @@ void vo_seek_reset(struct vo *vo)
{
vo_control(vo, VOCTRL_RESET, NULL);
vo->frame_loaded = false;
+ vo->hasframe = false;
}
void vo_destroy(struct vo *vo)
diff --git a/libvo/video_out.h b/libvo/video_out.h
index 554b97d207..3dd3ca8a8d 100644
--- a/libvo/video_out.h
+++ b/libvo/video_out.h
@@ -378,7 +378,6 @@ struct vo_rect {
void calc_src_dst_rects(struct vo *vo, int src_width, int src_height,
struct vo_rect *src, struct vo_rect *dst,
struct vo_rect *borders, const struct vo_rect *crop);
-struct input_ctx;
void vo_mouse_movement(struct vo *vo, int posx, int posy);
static inline int aspect_scaling(void)
diff --git a/libvo/vo_quartz.c b/libvo/vo_quartz.c
deleted file mode 100644
index 9098598aa8..0000000000
--- a/libvo/vo_quartz.c
+++ /dev/null
@@ -1,1371 +0,0 @@
-/*
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/**
- \author Nicolas Plourde <nicolasplourde@gmail.com>
-
- Copyright (c) Nicolas Plourde - April 2004
-
- YUV support Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
-
- \brief MPlayer Mac OSX Quartz video out module.
-
- \todo: -screen overlay output
- -fit osd in black bar when available
- -fix RGB32
- -(add sugestion here)
-*/
-
-//SYS
-#include <stdio.h>
-
-//OSX
-#include <Carbon/Carbon.h>
-#include <QuickTime/QuickTime.h>
-
-//MPLAYER
-#include "config.h"
-#include "fastmemcpy.h"
-#include "video_out.h"
-#include "video_out_internal.h"
-#include "aspect.h"
-#include "mp_msg.h"
-#include "m_option.h"
-#include "mp_fifo.h"
-#include "mpbswap.h"
-#include "sub/sub.h"
-
-#include "input/input.h"
-#include "input/keycodes.h"
-
-#include "osx_common.h"
-
-static const vo_info_t info =
-{
- "Mac OSX (Quartz)",
- "quartz",
- "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
- ""
-};
-
-const LIBVO_EXTERN(quartz)
-
-static uint32_t image_depth;
-static uint32_t image_format;
-static uint32_t image_size;
-static uint32_t image_buffer_size;
-static char *image_data;
-
-static ImageSequence seqId;
-static CodecType image_qtcodec;
-static PlanarPixmapInfoYUV420 *P = NULL;
-static struct
-{
- ImageDescriptionHandle desc;
- Handle extension_colr;
- Handle extension_fiel;
- Handle extension_clap;
- Handle extension_pasp;
-} yuv_qt_stuff;
-static MatrixRecord matrix;
-static int EnterMoviesDone = 0;
-static int get_image_done = 0;
-
-static int vo_quartz_fs; // we are in fullscreen
-
-static int winLevel = 1;
-int levelList[] =
-{
- kCGDesktopWindowLevelKey,
- kCGNormalWindowLevelKey,
- kCGScreenSaverWindowLevelKey
-};
-
-static int int_pause = 0;
-static float winAlpha = 1;
-static int mouseHide = FALSE;
-static float winSizeMult = 1;
-
-static int device_id = 0;
-
-static short fs_res_x = 0;
-static short fs_res_y = 0;
-
-static WindowRef theWindow = NULL;
-static WindowGroupRef winGroup = NULL;
-static CGRect bounds;
-static CGDirectDisplayID displayId = 0;
-static CFDictionaryRef originalMode = NULL;
-
-static CGDataProviderRef dataProviderRef = NULL;
-static CGImageRef image = NULL;
-
-static Rect imgRect; // size of the original image (unscaled)
-static Rect dstRect; // size of the displayed image (after scaling)
-static Rect winRect; // size of the window containg the displayed image (include padding)
-static Rect oldWinRect; // size of the window containg the displayed image (include padding) when NOT in FS mode
-static Rect oldWinBounds;
-
-static MenuRef windMenu;
-static MenuRef movMenu;
-static MenuRef aspectMenu;
-
-static int lastScreensaverUpdate = 0;
-static int lastMouseHide = 0;
-
-enum
-{
- kHalfScreenCmd = 2,
- kNormalScreenCmd = 3,
- kDoubleScreenCmd = 4,
- kFullScreenCmd = 5,
- kKeepAspectCmd = 6,
- kAspectOrgCmd = 7,
- kAspectFullCmd = 8,
- kAspectWideCmd = 9,
- kPanScanCmd = 10
-};
-
-//PROTOTYPE/////////////////////////////////////////////////////////////////
-static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
-static OSStatus MouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
-static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
-void window_resized(void);
-void window_ontop(void);
-void window_fullscreen(void);
-void window_panscan(void);
-
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
-{
- switch (image_format)
- {
- case IMGFMT_RGB32:
- vo_draw_alpha_rgb32(w, h, src, srca, stride, image_data + 4 * (y0 * imgRect.right + x0), 4 * imgRect.right);
- break;
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- vo_draw_alpha_yv12(w, h, src, srca, stride, ((char *)P) + be2me_32(P->componentInfoY.offset) + x0 + y0 * imgRect.right, imgRect.right);
- break;
- case IMGFMT_UYVY:
- vo_draw_alpha_uyvy(w, h, src, srca, stride, ((char *)P) + (x0 + y0 * imgRect.right) * 2, imgRect.right * 2);
- break;
- case IMGFMT_YUY2:
- vo_draw_alpha_yuy2(w, h, src, srca, stride, ((char *)P) + (x0 + y0 * imgRect.right) * 2, imgRect.right * 2);
- break;
- }
-}
-
-//default keyboard event handler
-static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
-{
- OSStatus result = noErr;
- UInt32 class = GetEventClass(event);
- UInt32 kind = GetEventKind(event);
-
- result = CallNextEventHandler(nextHandler, event);
-
- if (class == kEventClassKeyboard)
- {
- char macCharCodes;
- UInt32 macKeyCode;
- UInt32 macKeyModifiers;
-
- GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(macCharCodes), NULL, &macCharCodes);
- GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(macKeyCode), NULL, &macKeyCode);
- GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(macKeyModifiers), NULL, &macKeyModifiers);
-
- if (macKeyModifiers != 256)
- {
- if (kind == kEventRawKeyRepeat || kind == kEventRawKeyDown)
- {
- int key = convert_key(macKeyCode, macCharCodes);
-
- if (key != -1)
- mplayer_put_key(key);
- }
- }
- else if (macKeyModifiers == 256)
- {
- switch (macCharCodes)
- {
- case '[': SetWindowAlpha(theWindow, winAlpha -= 0.05); break;
- case ']': SetWindowAlpha(theWindow, winAlpha += 0.05); break;
- }
- }
- else
- result = eventNotHandledErr;
- }
-
- return result;
-}
-
-//default mouse event handler
-static OSStatus MouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
-{
- OSStatus result = noErr;
- UInt32 class = GetEventClass(event);
- UInt32 kind = GetEventKind(event);
-
- result = CallNextEventHandler(nextHandler, event);
-
- if (class == kEventClassMouse)
- {
- WindowPtr tmpWin;
- Point mousePos;
- Point winMousePos;
-
- GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(mousePos), 0, &mousePos);
- GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, 0, sizeof(winMousePos), 0, &winMousePos);
-
- switch (kind)
- {
- case kEventMouseMoved:
- {
- if (vo_quartz_fs)
- {
- CGDisplayShowCursor(displayId);
- mouseHide = FALSE;
- }
- }
- break;
-
- case kEventMouseWheelMoved:
- {
- int wheel;
- short part;
-
- GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, sizeof(wheel), 0, &wheel);
-
- part = FindWindow(mousePos, &tmpWin);
-
- if (part == inContent)
- {
- if (wheel > 0)
- mplayer_put_key(MOUSE_BTN3);
- else
- mplayer_put_key(MOUSE_BTN4);
- }
- }
- break;
-
- case kEventMouseDown:
- case kEventMouseUp:
- {
- EventMouseButton button;
- short part;
- Rect bounds;
-
- GetWindowPortBounds(theWindow, &bounds);
- GetEventParameter(event, kEventParamMouseButton, typeMouseButton, 0, sizeof(button), 0, &button);
-
- part = FindWindow(mousePos, &tmpWin);
- if (kind == kEventMouseUp)
- {
- if (part != inContent)
- break;
- switch (button)
- {
- case kEventMouseButtonPrimary:
- mplayer_put_key(MOUSE_BTN0);
- break;
- case kEventMouseButtonSecondary:
- mplayer_put_key(MOUSE_BTN2);
- break;
- case kEventMouseButtonTertiary:
- mplayer_put_key(MOUSE_BTN1);
- break;
-
- default:
- result = eventNotHandledErr;
- break;
- }
- break;
- }
- if (winMousePos.h > bounds.right - 15 && winMousePos.v > bounds.bottom)
- {
- if (!vo_quartz_fs)
- {
- Rect newSize;
-
- ResizeWindow(theWindow, mousePos, NULL, &newSize);
- }
- }
- else if (part == inMenuBar)
- {
- MenuSelect(mousePos);
- HiliteMenu(0);
- }
- else if (part == inContent)
- {
- switch (button)
- {
- case kEventMouseButtonPrimary:
- mplayer_put_key(MOUSE_BTN0 | MP_KEY_DOWN);
- break;
- case kEventMouseButtonSecondary:
- mplayer_put_key(MOUSE_BTN2 | MP_KEY_DOWN);
- break;
- case kEventMouseButtonTertiary:
- mplayer_put_key(MOUSE_BTN1 | MP_KEY_DOWN);
- break;
-
- default:
- result = eventNotHandledErr;
- break;
- }
- }
- }
- break;
-
- case kEventMouseDragged:
- break;
-
- default:
- result = eventNotHandledErr;
- break;
- }
- }
-
- return result;
-}
-
-static void set_winSizeMult(float mult)
-{
- int d_width, d_height;
- aspect(&d_width, &d_height, A_NOZOOM);
-
- if (vo_quartz_fs)
- {
- vo_fs = !vo_fs;
- window_fullscreen();
- }
-
- winSizeMult = mult;
- SizeWindow(theWindow, d_width * mult, d_height * mult, 1);
- window_resized();
-}
-
-//default window event handler
-static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
-{
- OSStatus result = noErr;
- UInt32 class = GetEventClass(event);
- UInt32 kind = GetEventKind(event);
-
- result = CallNextEventHandler(nextHandler, event);
-
- if (class == kEventClassCommand)
- {
- HICommand theHICommand;
-
- GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(theHICommand), NULL, &theHICommand);
-
- switch (theHICommand.commandID)
- {
- case kHICommandQuit:
- mplayer_put_key(KEY_CLOSE_WIN);
- break;
-
- case kHalfScreenCmd:
- set_winSizeMult(0.5);
- break;
-
- case kNormalScreenCmd:
- set_winSizeMult(1);
- break;
-
- case kDoubleScreenCmd:
- set_winSizeMult(2);
- break;
-
- case kFullScreenCmd:
- vo_fs = !vo_fs;
- window_fullscreen();
- break;
-
- case kKeepAspectCmd:
- vo_keepaspect = !vo_keepaspect;
- CheckMenuItem(aspectMenu, 1, vo_keepaspect);
- window_resized();
- break;
-
- case kAspectOrgCmd:
- change_movie_aspect(-1);
- break;
-
- case kAspectFullCmd:
- change_movie_aspect(4.0 / 3.0);
- break;
-
- case kAspectWideCmd:
- change_movie_aspect(16.0 / 9.0);
- break;
-
- case kPanScanCmd:
- vo_panscan = !vo_panscan;
- CheckMenuItem(aspectMenu, 2, vo_panscan);
- window_panscan();
- window_resized();
- break;
-
- default:
- result = eventNotHandledErr;
- break;
- }
- }
- else if (class == kEventClassWindow)
- {
- WindowRef window;
- Rect rectWindow = { 0, 0, 0, 0 };
-
- GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(window), NULL, &window);
-
- if (window)
- {
- GetWindowBounds(window, kWindowGlobalPortRgn, &rectWindow);
- }
-
- switch (kind)
- {
- case kEventWindowClosed:
- theWindow = NULL;
- mplayer_put_key(KEY_CLOSE_WIN);
- break;
-
- // resize window
- case kEventWindowZoomed:
- case kEventWindowBoundsChanged:
- window_resized();
- flip_page();
- window_resized();
- break;
-
- default:
- result = eventNotHandledErr;
- break;
- }
- }
-
- return result;
-}
-
-static void quartz_CreateWindow(uint32_t d_width, uint32_t d_height, WindowAttributes windowAttrs)
-{
- CFStringRef titleKey;
- CFStringRef windowTitle;
- OSStatus result;
-
- MenuItemIndex index;
- CFStringRef movMenuTitle;
- CFStringRef aspMenuTitle;
-
- const EventTypeSpec win_events[] = {
- {kEventClassWindow, kEventWindowClosed},
- {kEventClassWindow, kEventWindowBoundsChanged},
- {kEventClassCommand, kEventCommandProcess}
- };
-
- const EventTypeSpec key_events[] = {
- {kEventClassKeyboard, kEventRawKeyDown},
- {kEventClassKeyboard, kEventRawKeyRepeat}
- };
-
- const EventTypeSpec mouse_events[] = {
- {kEventClassMouse, kEventMouseMoved},
- {kEventClassMouse, kEventMouseWheelMoved},
- {kEventClassMouse, kEventMouseDown},
- {kEventClassMouse, kEventMouseUp},
- {kEventClassMouse, kEventMouseDragged}
- };
-
- SetRect(&winRect, 0, 0, d_width, d_height);
- SetRect(&oldWinRect, 0, 0, d_width, d_height);
- SetRect(&dstRect, 0, 0, d_width, d_height);
-
- // Clear Menu Bar
- ClearMenuBar();
-
- // Create Window Menu
- CreateStandardWindowMenu(0, &windMenu);
- InsertMenu(windMenu, 0);
-
- // Create Movie Menu
- CreateNewMenu(1004, 0, &movMenu);
- movMenuTitle = CFSTR("Movie");
- SetMenuTitleWithCFString(movMenu, movMenuTitle);
-
- AppendMenuItemTextWithCFString(movMenu, CFSTR("Half Size"), 0, kHalfScreenCmd, &index);
- SetMenuItemCommandKey(movMenu, index, 0, '0');
-
- AppendMenuItemTextWithCFString(movMenu, CFSTR("Normal Size"), 0, kNormalScreenCmd, &index);
- SetMenuItemCommandKey(movMenu, index, 0, '1');
-
- AppendMenuItemTextWithCFString(movMenu, CFSTR("Double Size"), 0, kDoubleScreenCmd, &index);
- SetMenuItemCommandKey(movMenu, index, 0, '2');
-
- AppendMenuItemTextWithCFString(movMenu, CFSTR("Full Size"), 0, kFullScreenCmd, &index);
- SetMenuItemCommandKey(movMenu, index, 0, 'F');
-
- AppendMenuItemTextWithCFString(movMenu, NULL, kMenuItemAttrSeparator, 0, &index);
-
- AppendMenuItemTextWithCFString(movMenu, CFSTR("Aspect Ratio"), 0, 0, &index);
-
- //// Create Aspect Ratio Sub Menu
- CreateNewMenu(0, 0, &aspectMenu);
- aspMenuTitle = CFSTR("Aspect Ratio");
- SetMenuTitleWithCFString(aspectMenu, aspMenuTitle);
- SetMenuItemHierarchicalMenu(movMenu, 6, aspectMenu);
-
- AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Keep"), 0, kKeepAspectCmd, &index);
- CheckMenuItem(aspectMenu, 1, vo_keepaspect);
- AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Pan-Scan"), 0, kPanScanCmd, &index);
- CheckMenuItem(aspectMenu, 2, vo_panscan);
- AppendMenuItemTextWithCFString(aspectMenu, NULL, kMenuItemAttrSeparator, 0, &index);
- AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Original"), 0, kAspectOrgCmd, &index);
- AppendMenuItemTextWithCFString(aspectMenu, CFSTR("4:3"), 0, kAspectFullCmd, &index);
- AppendMenuItemTextWithCFString(aspectMenu, CFSTR("16:9"), 0, kAspectWideCmd, &index);
-
- InsertMenu(movMenu, GetMenuID(windMenu)); //insert before Window menu
-
- DrawMenuBar();
-
- // create window
- CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow);
-
- CreateWindowGroup(0, &winGroup);
- SetWindowGroup(theWindow, winGroup);
-
- // Set window title
- titleKey = CFSTR("MPlayer - The Movie Player");
- windowTitle = CFCopyLocalizedString(titleKey, NULL);
- result = SetWindowTitleWithCFString(theWindow, windowTitle);
- CFRelease(titleKey);
- CFRelease(windowTitle);
-
- // Install event handler
- InstallApplicationEventHandler(NewEventHandlerUPP(KeyEventHandler), GetEventTypeCount(key_events), key_events, NULL, NULL);
- InstallApplicationEventHandler(NewEventHandlerUPP(MouseEventHandler), GetEventTypeCount(mouse_events), mouse_events, NULL, NULL);
- InstallWindowEventHandler(theWindow, NewEventHandlerUPP(WindowEventHandler), GetEventTypeCount(win_events), win_events, theWindow, NULL);
-}
-
-static void update_screen_info(void)
-{
- CGRect displayRect;
- CGDisplayCount displayCount;
- CGDirectDisplayID *displays;
- // Display IDs might not be consecutive, get the list of all devices up to # device_id
- displayCount = device_id + 1;
- displays = malloc(sizeof(*displays) * displayCount);
- if (kCGErrorSuccess != CGGetActiveDisplayList(displayCount, displays, &displayCount) || displayCount < device_id + 1) {
- mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id);
- displayId = kCGDirectMainDisplay;
- device_id = 0;
- }
- else
- {
- displayId = displays[device_id];
- }
- free(displays);
-
- displayRect = CGDisplayBounds(displayId);
- xinerama_x = displayRect.origin.x;
- xinerama_y = displayRect.origin.y;
- vo_screenwidth = displayRect.size.width;
- vo_screenheight = displayRect.size.height;
- aspect_save_screenres(vo_screenwidth, vo_screenheight);
-}
-
-static void free_video_specific(void)
-{
- if (seqId) CDSequenceEnd(seqId);
- seqId = 0;
- free(image_data);
- image_data = NULL;
- free(P);
- P = NULL;
- CGDataProviderRelease(dataProviderRef);
- dataProviderRef = NULL;
- CGImageRelease(image);
- image = NULL;
-}
-
-static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
-{
- WindowAttributes windowAttrs;
- OSErr qterr;
- CGRect tmpBounds;
-
- free_video_specific();
-
- vo_dwidth = d_width *= winSizeMult;
- vo_dheight = d_height *= winSizeMult;
- config_movie_aspect((float)d_width / d_height);
-
- // misc mplayer setup/////////////////////////////////////////////////////
- SetRect(&imgRect, 0, 0, width, height);
- switch (image_format)
- {
- case IMGFMT_RGB32:
- image_depth = 32;
- break;
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- image_depth = 16;
- break;
- }
- image_size = (imgRect.right * imgRect.bottom * image_depth + 7) / 8;
-
- image_data = malloc(image_size);
-
- // Create player window//////////////////////////////////////////////////
- windowAttrs = kWindowStandardDocumentAttributes
- | kWindowStandardHandlerAttribute
- | kWindowLiveResizeAttribute;
-
- windowAttrs &= ~kWindowResizableAttribute;
-
- if (theWindow == NULL)
- {
- CGContextRef context;
-
- quartz_CreateWindow(d_width, d_height, windowAttrs);
-
- if (theWindow == NULL)
- {
- mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: Couldn't create window !!!!!\n");
- return -1;
- }
- tmpBounds = CGRectMake(0, 0, winRect.right, winRect.bottom);
- QDBeginCGContext(GetWindowPort(theWindow), &context);
- CGContextFillRect(context, tmpBounds);
- QDEndCGContext(GetWindowPort(theWindow), &context);
- }
- else
- {
- HideWindow(theWindow);
- ChangeWindowAttributes(theWindow, ~windowAttrs, windowAttrs);
- SetRect(&winRect, 0, 0, d_width, d_height);
- SetRect(&oldWinRect, 0, 0, d_width, d_height);
- SizeWindow(theWindow, d_width, d_height, 1);
- }
-
- switch (image_format)
- {
- case IMGFMT_RGB32:
- {
- CGContextRef context;
-
- QDBeginCGContext(GetWindowPort(theWindow), &context);
-
- dataProviderRef = CGDataProviderCreateWithData(0, image_data, imgRect.right * imgRect.bottom * 4, 0);
-
- image = CGImageCreate(imgRect.right,
- imgRect.bottom,
- 8,
- image_depth,
- (imgRect.right * 32 + 7) / 8,
- CGColorSpaceCreateDeviceRGB(),
- kCGImageAlphaNoneSkipFirst,
- dataProviderRef, 0, 1, kCGRenderingIntentDefault);
-
- QDEndCGContext(GetWindowPort(theWindow), &context);
- break;
- }
-
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- {
- get_image_done = 0;
-
- if (!EnterMoviesDone)
- {
- qterr = EnterMovies();
- EnterMoviesDone = 1;
- }
- else
- qterr = 0;
-
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: EnterMovies (%d)\n", qterr);
- return -1;
- }
-
-
- SetIdentityMatrix(&matrix);
-
- if (d_width != width || d_height != height)
- {
- ScaleMatrix(&matrix, FixDiv(Long2Fix(d_width), Long2Fix(width)), FixDiv(Long2Fix(d_height), Long2Fix(height)), 0, 0);
- }
-
- yuv_qt_stuff.desc = (ImageDescriptionHandle) NewHandleClear(sizeof(ImageDescription));
-
- yuv_qt_stuff.extension_colr = NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension));
- ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->colorParamType = kVideoColorInfoImageDescriptionExtensionType;
- ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->primaries = 2;
- ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->transferFunction = 2;
- ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->matrix = 2;
-
- yuv_qt_stuff.extension_fiel = NewHandleClear(sizeof(FieldInfoImageDescriptionExtension));
- ((FieldInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_fiel))->fieldCount = 1;
- ((FieldInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_fiel))->fieldOrderings = 0;
-
- yuv_qt_stuff.extension_clap = NewHandleClear(sizeof(CleanApertureImageDescriptionExtension));
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureWidthN = imgRect.right;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureWidthD = 1;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureHeightN = imgRect.bottom;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureHeightD = 1;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->horizOffN = 0;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->horizOffD = 1;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->vertOffN = 0;
- ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->vertOffD = 1;
-
- yuv_qt_stuff.extension_pasp = NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension));
- ((PixelAspectRatioImageDescriptionExtension *) (*yuv_qt_stuff.extension_pasp))->hSpacing = 1;
- ((PixelAspectRatioImageDescriptionExtension *) (*yuv_qt_stuff.extension_pasp))->vSpacing = 1;
-
- (*yuv_qt_stuff.desc)->idSize = sizeof(ImageDescription);
- (*yuv_qt_stuff.desc)->cType = image_qtcodec;
- (*yuv_qt_stuff.desc)->version = 2;
- (*yuv_qt_stuff.desc)->revisionLevel = 0;
- (*yuv_qt_stuff.desc)->vendor = 'mpla';
- (*yuv_qt_stuff.desc)->width = imgRect.right;
- (*yuv_qt_stuff.desc)->height = imgRect.bottom;
- (*yuv_qt_stuff.desc)->hRes = Long2Fix(72);
- (*yuv_qt_stuff.desc)->vRes = Long2Fix(72);
- (*yuv_qt_stuff.desc)->temporalQuality = 0;
- (*yuv_qt_stuff.desc)->spatialQuality = codecLosslessQuality;
- (*yuv_qt_stuff.desc)->frameCount = 1;
- (*yuv_qt_stuff.desc)->dataSize = 0;
- (*yuv_qt_stuff.desc)->depth = 24;
- (*yuv_qt_stuff.desc)->clutID = -1;
-
- qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_colr, kColorInfoImageDescriptionExtension);
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr);
- }
-
- qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_fiel, kFieldInfoImageDescriptionExtension);
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr);
- }
-
- qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_clap, kCleanApertureImageDescriptionExtension);
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr);
- }
-
- qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_pasp, kCleanApertureImageDescriptionExtension);
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr);
- }
- P = calloc(sizeof(PlanarPixmapInfoYUV420) + image_size, 1);
- switch (image_format)
- {
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- P->componentInfoY.offset = be2me_32(sizeof(PlanarPixmapInfoYUV420));
- P->componentInfoCb.offset = be2me_32(be2me_32(P->componentInfoY.offset) + image_size / 2);
- P->componentInfoCr.offset = be2me_32(be2me_32(P->componentInfoCb.offset) + image_size / 4);
- P->componentInfoY.rowBytes = be2me_32(imgRect.right);
- P->componentInfoCb.rowBytes = be2me_32(imgRect.right / 2);
- P->componentInfoCr.rowBytes = be2me_32(imgRect.right / 2);
- image_buffer_size = image_size + sizeof(PlanarPixmapInfoYUV420);
- break;
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- image_buffer_size = image_size;
- break;
- }
-
- qterr = DecompressSequenceBeginS(&seqId,
- yuv_qt_stuff.desc,
- (char *)P,
- image_buffer_size,
- GetWindowPort(theWindow),
- NULL,
- NULL,
- d_width != width || d_height != height ?
- &matrix : NULL,
- srcCopy,
- NULL,
- 0,
- codecLosslessQuality,
- bestSpeedCodec);
-
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr);
- return -1;
- }
- }
- break;
- }
-
- // Show window
- RepositionWindow(theWindow, NULL, kWindowCenterOnMainScreen);
- ShowWindow(theWindow);
-
- if (vo_fs)
- window_fullscreen();
-
- if (vo_ontop)
- window_ontop();
-
- if (vo_rootwin)
- {
- vo_fs = TRUE;
- winLevel = 0;
- SetWindowGroupLevel(winGroup, CGWindowLevelForKey(levelList[winLevel]));
- window_fullscreen();
- }
-
- window_resized();
-
- return 0;
-}
-
-static void check_events(void)
-{
- EventRef theEvent;
- EventTargetRef theTarget;
- OSStatus theErr;
-
- // Get event
- theTarget = GetEventDispatcherTarget();
- theErr = ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &theEvent);
- if (theErr == noErr && theEvent != NULL)
- {
- SendEventToEventTarget(theEvent, theTarget);
- ReleaseEvent(theEvent);
- }
-}
-
-static void draw_osd(void)
-{
- vo_draw_text(imgRect.right, imgRect.bottom, draw_alpha);
-}
-
-static void flip_page(void)
-{
- int curTime;
-
- if (theWindow == NULL)
- return;
-
- switch (image_format)
- {
- case IMGFMT_RGB32:
- {
- CGContextRef context;
-
- QDBeginCGContext(GetWindowPort(theWindow), &context);
- CGContextDrawImage(context, bounds, image);
- QDEndCGContext(GetWindowPort(theWindow), &context);
- }
- break;
-
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- if (EnterMoviesDone)
- {
- OSErr qterr;
- CodecFlags flags = 0;
-
- qterr = DecompressSequenceFrameWhen(seqId,
- (char *)P,
- image_buffer_size,
- 0, //codecFlagUseImageBuffer,
- &flags,
- NULL,
- NULL);
- if (qterr)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr, flags);
- }
- }
- break;
- }
-
- if (!vo_quartz_fs)
- {
- CGContextRef context;
-
- QDBeginCGContext(GetWindowPort(theWindow), &context);
- // render resize box
- CGContextBeginPath(context);
- CGContextSetAllowsAntialiasing(context, false);
- //CGContextSaveGState(context);
-
- // line white
- CGContextSetRGBStrokeColor(context, 0.2, 0.2, 0.2, 0.5);
- CGContextMoveToPoint(context, winRect.right - 1, 1); CGContextAddLineToPoint(context, winRect.right - 1, 1);
- CGContextMoveToPoint(context, winRect.right - 1, 5); CGContextAddLineToPoint(context, winRect.right - 5, 1);
- CGContextMoveToPoint(context, winRect.right - 1, 9); CGContextAddLineToPoint(context, winRect.right - 9, 1);
- CGContextStrokePath(context);
-
- // line gray
- CGContextSetRGBStrokeColor(context, 0.4, 0.4, 0.4, 0.5);
- CGContextMoveToPoint(context, winRect.right - 1, 2); CGContextAddLineToPoint(context, winRect.right - 2, 1);
- CGContextMoveToPoint(context, winRect.right - 1, 6); CGContextAddLineToPoint(context, winRect.right - 6, 1);
- CGContextMoveToPoint(context, winRect.right - 1, 10); CGContextAddLineToPoint(context, winRect.right - 10, 1);
- CGContextStrokePath(context);
-
- // line black
- CGContextSetRGBStrokeColor(context, 0.6, 0.6, 0.6, 0.5);
- CGContextMoveToPoint(context, winRect.right - 1, 3); CGContextAddLineToPoint(context, winRect.right - 3, 1);
- CGContextMoveToPoint(context, winRect.right - 1, 7); CGContextAddLineToPoint(context, winRect.right - 7, 1);
- CGContextMoveToPoint(context, winRect.right - 1, 11); CGContextAddLineToPoint(context, winRect.right - 11, 1);
- CGContextStrokePath(context);
-
- // CGContextRestoreGState( context );
- CGContextFlush(context);
- QDEndCGContext(GetWindowPort(theWindow), &context);
- }
-
- curTime = TickCount() / 60;
-
- // auto hide mouse cursor (and future on-screen control?)
- if (vo_quartz_fs && !mouseHide)
- {
- if (curTime - lastMouseHide >= 5 || lastMouseHide == 0)
- {
- CGDisplayHideCursor(displayId);
- mouseHide = TRUE;
- lastMouseHide = curTime;
- }
- }
- // update activity every 30 seconds to prevent
- // screensaver from starting up.
- if (curTime - lastScreensaverUpdate >= 30 || lastScreensaverUpdate == 0)
- {
- UpdateSystemActivity(UsrActivity);
- lastScreensaverUpdate = curTime;
- }
-}
-
-static int draw_slice(uint8_t * src[], int stride[], int w, int h, int x, int y)
-{
- switch (image_format)
- {
- case IMGFMT_YV12:
- case IMGFMT_I420:
- memcpy_pic(((char *)P) + be2me_32(P->componentInfoY.offset) + x + imgRect.right * y, src[0], w, h, imgRect.right, stride[0]);
- x=x/2;y=y/2;w=w/2;h=h/2;
-
- memcpy_pic(((char *)P) + be2me_32(P->componentInfoCb.offset) + x + imgRect.right / 2 * y, src[1], w, h, imgRect.right / 2, stride[1]);
- memcpy_pic(((char *)P) + be2me_32(P->componentInfoCr.offset) + x + imgRect.right / 2 * y, src[2], w, h, imgRect.right / 2, stride[2]);
- return 0;
-
- case IMGFMT_IYUV:
- memcpy_pic(((char *)P) + be2me_32(P->componentInfoY.offset) + x + imgRect.right * y, src[0], w, h, imgRect.right, stride[0]);
- x=x/2;y=y/2;w=w/2;h=h/2;
-
- memcpy_pic(((char *)P) + be2me_32(P->componentInfoCr.offset) + x + imgRect.right / 2 * y, src[1], w, h, imgRect.right / 2, stride[1]);
- memcpy_pic(((char *)P) + be2me_32(P->componentInfoCb.offset) + x + imgRect.right / 2 * y, src[2], w, h, imgRect.right / 2, stride[2]);
- return 0;
- }
- return -1;
-}
-
-static int draw_frame(uint8_t * src[])
-{
- switch (image_format)
- {
- case IMGFMT_RGB32:
- fast_memcpy(image_data, src[0], image_size);
- return 0;
-
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- memcpy_pic(((char *)P), src[0], imgRect.right * 2, imgRect.bottom, imgRect.right * 2, imgRect.right * 2);
- return 0;
- }
- return -1;
-}
-
-static int query_format(uint32_t format)
-{
- image_format = format;
- image_qtcodec = 0;
-
- if (format == IMGFMT_RGB32)
- {
- return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
- }
-
- if (format == IMGFMT_YV12 || format == IMGFMT_IYUV || format == IMGFMT_I420)
- {
- image_qtcodec = kMpegYUV420CodecType; //kYUV420CodecType ?;
- return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE;
- }
-
- if (format == IMGFMT_YUY2)
- {
- image_qtcodec = kComponentVideoUnsigned;
- return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
- }
-
- if (format == IMGFMT_UYVY)
- {
- image_qtcodec = k422YpCbCr8CodecType;
- return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
- }
-
- return 0;
-}
-
-static void uninit(void)
-{
- free_video_specific();
- if (EnterMoviesDone)
- ExitMovies();
- EnterMoviesDone = 0;
-
- ShowMenuBar();
-}
-
-static int preinit(const char *arg)
-{
- int parse_err = 0;
-
- if(arg)
- {
- char *parse_pos = (char *)&arg[0];
-
- while (parse_pos[0] && !parse_err)
- {
- if (strncmp(parse_pos, "device_id=", 10) == 0)
- {
- parse_pos = &parse_pos[10];
- device_id = strtol(parse_pos, &parse_pos, 0);
- }
- if (strncmp(parse_pos, "fs_res=", 7) == 0)
- {
- parse_pos = &parse_pos[7];
- fs_res_x = strtol(parse_pos, &parse_pos, 0);
- parse_pos = &parse_pos[1];
- fs_res_y = strtol(parse_pos, &parse_pos, 0);
- }
- if (parse_pos[0] == ':')
- parse_pos = &parse_pos[1];
- else if (parse_pos[0])
- parse_err = 1;
- }
- }
-
- osx_foreground_hack();
-
- return 0;
-}
-
-static uint32_t draw_yuv_image(mp_image_t * mpi)
-{
- // ATM we're only called for planar IMGFMT
- // drawing is done directly in P
- // and displaying is in flip_page.
- return get_image_done ? VO_TRUE : VO_FALSE;
-}
-
-static uint32_t get_yuv_image(mp_image_t * mpi)
-{
- if (mpi->type != MP_IMGTYPE_EXPORT) return VO_FALSE;
-
- if (mpi->imgfmt != image_format) return VO_FALSE;
-
- if (mpi->flags & MP_IMGFLAG_PLANAR)
- {
- if (mpi->num_planes != 3)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi->num_planes);
- return VO_FALSE;
- }
-
- mpi->planes[0] = ((char *)P) + be2me_32(P->componentInfoY.offset);
- mpi->stride[0] = imgRect.right;
- mpi->width = imgRect.right;
-
- if (mpi->flags & MP_IMGFLAG_SWAPPED)
- {
- // I420
- mpi->planes[1] = ((char *)P) + be2me_32(P->componentInfoCb.offset);
- mpi->planes[2] = ((char *)P) + be2me_32(P->componentInfoCr.offset);
- mpi->stride[1] = imgRect.right / 2;
- mpi->stride[2] = imgRect.right / 2;
- }
- else
- {
- // YV12
- mpi->planes[1] = ((char *)P) + be2me_32(P->componentInfoCr.offset);
- mpi->planes[2] = ((char *)P) + be2me_32(P->componentInfoCb.offset);
- mpi->stride[1] = imgRect.right / 2;
- mpi->stride[2] = imgRect.right / 2;
- }
-
- mpi->flags |= MP_IMGFLAG_DIRECT;
- get_image_done = 1;
- return VO_TRUE;
- }
- else
- {
- // doesn't work yet
- if (mpi->num_planes != 1)
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi->num_planes);
- return VO_FALSE;
- }
-
- mpi->planes[0] = (char *)P;
- mpi->stride[0] = imgRect.right * 2;
- mpi->width = imgRect.right;
- mpi->flags |= MP_IMGFLAG_DIRECT;
- get_image_done = 1;
- return VO_TRUE;
- }
- return VO_FALSE;
-}
-
-static int control(uint32_t request, void *data)
-{
- switch (request)
- {
- case VOCTRL_PAUSE: return int_pause = 1;
- case VOCTRL_RESUME: return int_pause = 0;
- case VOCTRL_FULLSCREEN: vo_fs = !vo_fs; window_fullscreen(); return VO_TRUE;
- case VOCTRL_ONTOP: vo_ontop = !vo_ontop; window_ontop(); return VO_TRUE;
- case VOCTRL_QUERY_FORMAT: return query_format(*(uint32_t *) data);
- case VOCTRL_GET_PANSCAN: return VO_TRUE;
- case VOCTRL_SET_PANSCAN: window_panscan(); return VO_TRUE;
-
- case VOCTRL_GET_IMAGE:
- switch (image_format)
- {
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- return get_yuv_image(data);
- break;
- default:
- break;
- }
- case VOCTRL_DRAW_IMAGE:
- switch (image_format)
- {
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- return draw_yuv_image(data);
- break;
- default:
- break;
- }
- case VOCTRL_UPDATE_SCREENINFO:
- update_screen_info();
- return VO_TRUE;
- }
- return VO_NOTIMPL;
-}
-
-void window_resized(void)
-{
- uint32_t d_width;
- uint32_t d_height;
-
- CGRect tmpBounds;
-
- CGContextRef context;
-
- GetWindowPortBounds(theWindow, &winRect);
- d_width = vo_dwidth = winRect.right;
- d_height = vo_dheight = winRect.bottom;
-
- if (vo_keepaspect)
- aspect(&d_width, &d_height, A_WINZOOM);
- SetRect(&dstRect, (vo_dwidth - d_width) / 2, (vo_dheight - d_height) / 2, d_width, d_height);
-
- switch (image_format)
- {
- case IMGFMT_RGB32:
- {
- bounds = CGRectMake(dstRect.left, dstRect.top, dstRect.right - dstRect.left, dstRect.bottom - dstRect.top);
- break;
- }
- case IMGFMT_YV12:
- case IMGFMT_IYUV:
- case IMGFMT_I420:
- case IMGFMT_UYVY:
- case IMGFMT_YUY2:
- {
- long scale_X = FixDiv(Long2Fix(dstRect.right - dstRect.left), Long2Fix(imgRect.right));
- long scale_Y = FixDiv(Long2Fix(dstRect.bottom - dstRect.top), Long2Fix(imgRect.bottom));
-
- SetIdentityMatrix(&matrix);
- if (dstRect.right - dstRect.left != imgRect.right || dstRect.bottom - dstRect.right != imgRect.bottom)
- {
- ScaleMatrix(&matrix, scale_X, scale_Y, 0, 0);
-
- if (vo_dwidth > d_width || vo_dheight > d_height)
- {
- TranslateMatrix(&matrix, Long2Fix(dstRect.left), Long2Fix(dstRect.top));
- }
- }
-
- SetDSequenceMatrix(seqId, &matrix);
- break;
- }
- default:
- break;
- }
-
- // Clear Background
- tmpBounds = CGRectMake(0, 0, winRect.right, winRect.bottom);
- QDBeginCGContext(GetWindowPort(theWindow), &context);
- CGContextFillRect(context, tmpBounds);
- QDEndCGContext(GetWindowPort(theWindow), &context);
-}
-
-void window_ontop(void)
-{
- if (!vo_quartz_fs)
- {
- // Cycle between level
- winLevel++;
- if (winLevel > 2)
- winLevel = 1;
- }
- SetWindowGroupLevel(winGroup, CGWindowLevelForKey(levelList[winLevel]));
-}
-
-void window_fullscreen(void)
-{
- // go fullscreen
- if (vo_fs)
- {
- if (winLevel != 0)
- {
- if (displayId == kCGDirectMainDisplay)
- {
- SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
- CGDisplayHideCursor(displayId);
- mouseHide = TRUE;
- }
-
- if (fs_res_x != 0 || fs_res_y != 0)
- {
- CFDictionaryRef mode;
- size_t desiredBitDepth = 32;
- boolean_t exactMatch;
-
- originalMode = CGDisplayCurrentMode(displayId);
-
- mode = CGDisplayBestModeForParameters(displayId, desiredBitDepth, fs_res_x, fs_res_y, &exactMatch);
-
- if (mode != NULL)
- {
- if (!exactMatch)
- {
- // Warn if the mode doesn't match exactly
- mp_msg(MSGT_VO, MSGL_WARN, "Quartz warning: did not get exact mode match (got %dx%d) \n", (int)CFDictionaryGetValue(mode, kCGDisplayWidth), (int)CFDictionaryGetValue(mode, kCGDisplayHeight));
- }
-
- CGDisplayCapture(displayId);
- CGDisplaySwitchToMode(displayId, mode);
- }
- else
- {
- mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: can't switch to fullscreen \n");
- }
-
- // Get Main device info///////////////////////////////////////////////////
- update_screen_info();
- }
- }
- // save old window size
- if (!vo_quartz_fs)
- {
- GetWindowPortBounds(theWindow, &oldWinRect);
- GetWindowBounds(theWindow, kWindowContentRgn, &oldWinBounds);
- }
- // go fullscreen
- ChangeWindowAttributes(theWindow, kWindowNoShadowAttribute, 0);
-
- vo_quartz_fs = 1;
- window_panscan();
- }
- else //go back to windowed mode
- {
- vo_quartz_fs = 0;
- if (originalMode != NULL)
- {
- CGDisplaySwitchToMode(displayId, originalMode);
- CGDisplayRelease(displayId);
-
- // Get Main device info///////////////////////////////////////////////////
- update_screen_info();
-
- originalMode = NULL;
- }
- SetSystemUIMode(kUIModeNormal, 0);
-
- // show mouse cursor
- CGDisplayShowCursor(displayId);
- mouseHide = FALSE;
-
- // revert window to previous setting
- ChangeWindowAttributes(theWindow, 0, kWindowNoShadowAttribute);
- SizeWindow(theWindow, oldWinRect.right, oldWinRect.bottom, 1);
- MoveWindow(theWindow, oldWinBounds.left, oldWinBounds.top, 1);
- }
- window_resized();
-}
-
-void window_panscan(void)
-{
- panscan_calc();
-
- if (vo_panscan > 0)
- CheckMenuItem(aspectMenu, 2, 1);
- else
- CheckMenuItem(aspectMenu, 2, 0);
-
- if (vo_quartz_fs)
- {
- MoveWindow(theWindow, xinerama_x - (vo_panscan_x >> 1), xinerama_y - (vo_panscan_y >> 1), 1);
- SizeWindow(theWindow, vo_screenwidth + vo_panscan_x, vo_screenheight + vo_panscan_y, 1);
- }
-}
diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c
index 4180ac0fd0..5bbcfc4d0a 100644
--- a/libvo/vo_xv.c
+++ b/libvo/vo_xv.c
@@ -18,29 +18,29 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-// Number of buffers _FOR_DOUBLEBUFFERING_MODE_
-// Use option -double to enable double buffering! (default: single buffer)
-#define NUM_BUFFERS 3
-
-/*
-Buffer allocation:
-
--nodr:
- 1: TEMP
- 2: 2*TEMP
-
--dr:
- 1: TEMP
- 3: 2*STATIC+TEMP
-*/
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
+#include <errno.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <libavutil/common.h>
#include "config.h"
+
+#ifdef HAVE_SHM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <X11/extensions/XShm.h>
+#endif
+
+// Note: depends on the inclusion of X11/extensions/XShm.h
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+
#include "options.h"
#include "talloc.h"
#include "mp_msg.h"
@@ -48,22 +48,13 @@ Buffer allocation:
#include "libmpcodecs/vfcap.h"
#include "libmpcodecs/mp_image.h"
#include "osd.h"
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <errno.h>
-
#include "x11_common.h"
-
#include "fastmemcpy.h"
#include "sub/sub.h"
#include "aspect.h"
#include "csputils.h"
-
#include "subopt-helper.h"
-#include "libavutil/common.h"
-
static const vo_info_t info = {
"X11/Xv",
"xv",
@@ -71,16 +62,6 @@ static const vo_info_t info = {
""
};
-#ifdef HAVE_SHM
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <X11/extensions/XShm.h>
-#endif
-
-// Note: depends on the inclusion of X11/extensions/XShm.h
-#include <X11/extensions/Xv.h>
-#include <X11/extensions/Xvlib.h>
-
struct xvctx {
XvAdaptorInfo *ai;
XvImageFormatValues *fo;
@@ -92,7 +73,7 @@ struct xvctx {
bool have_image_copy;
bool unchanged_image;
int visible_buf;
- XvImage *xvimage[NUM_BUFFERS + 1];
+ XvImage *xvimage[2 + 1];
uint32_t image_width;
uint32_t image_height;
uint32_t image_format;
@@ -108,7 +89,7 @@ struct xvctx {
unsigned char *src, unsigned char *srca,
int stride);
#ifdef HAVE_SHM
- XShmSegmentInfo Shminfo[NUM_BUFFERS + 1];
+ XShmSegmentInfo Shminfo[2 + 1];
int Shmem_Flag;
#endif
};
@@ -301,8 +282,7 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
for (i = 0; i < ctx->total_buffers; i++)
deallocate_xvimage(vo, i);
- ctx->num_buffers =
- vo_doublebuffering ? (vo_directrendering ? NUM_BUFFERS : 2) : 1;
+ ctx->num_buffers = 2;
ctx->total_buffers = ctx->num_buffers + 1;
for (i = 0; i < ctx->total_buffers; i++)
@@ -462,12 +442,8 @@ static void flip_page(struct vo *vo)
/* remember the currently visible buffer */
ctx->visible_buf = ctx->current_buf;
- if (ctx->num_buffers > 1) {
- ctx->current_buf = vo_directrendering ? 0 : ((ctx->current_buf + 1) %
- ctx->num_buffers);
- XFlush(vo->x11->display);
- } else
- XSync(vo->x11->display, False);
+ ctx->current_buf = (ctx->current_buf + 1) % ctx->num_buffers;
+ XFlush(vo->x11->display);
return;
}
@@ -553,10 +529,7 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
ctx->have_image_copy = false;
- if (mpi->flags & MP_IMGFLAG_DIRECT)
- // direct rendering:
- ctx->current_buf = (size_t)(mpi->priv); // hack!
- else if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
+ if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
; // done
else if (mpi->flags & MP_IMGFLAG_PLANAR)
draw_slice(vo, mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0);
@@ -577,66 +550,6 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
return true;
}
-static uint32_t get_image(struct xvctx *ctx, mp_image_t *mpi)
-{
- // we shouldn't change current_buf unless we do DR!
- int buf = ctx->current_buf;
-
- if (mpi->type == MP_IMGTYPE_STATIC && ctx->num_buffers > 1)
- return VO_FALSE; // it is not static
- if (mpi->imgfmt != ctx->image_format)
- return VO_FALSE; // needs conversion :(
- if (mpi->flags & MP_IMGFLAG_READABLE
- && (mpi->type == MP_IMGTYPE_IPB || mpi->type == MP_IMGTYPE_IP)) {
- // reference (I/P) frame of IP or IPB:
- if (ctx->num_buffers < 2)
- return VO_FALSE; // not enough
- ctx->current_ip_buf ^= 1;
- // for IPB with 2 buffers we can DR only one of the 2 P frames:
- if (mpi->type == MP_IMGTYPE_IPB && ctx->num_buffers < 3
- && ctx->current_ip_buf)
- return VO_FALSE;
- buf = ctx->current_ip_buf;
- if (mpi->type == MP_IMGTYPE_IPB)
- ++buf; // preserve space for B
- }
- if (mpi->height > ctx->xvimage[buf]->height)
- return VO_FALSE; //buffer to small
- if (mpi->width * (mpi->bpp / 8) > ctx->xvimage[buf]->pitches[0])
- return VO_FALSE; //buffer to small
- if ((mpi->flags & (MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_ACCEPT_WIDTH))
- || (mpi->width * (mpi->bpp / 8) == ctx->xvimage[buf]->pitches[0])) {
- ctx->current_buf = buf;
- XvImage *current_image = ctx->xvimage[ctx->current_buf];
- mpi->planes[0] = current_image->data + current_image->offsets[0];
- mpi->stride[0] = current_image->pitches[0];
- mpi->width = mpi->stride[0] / (mpi->bpp / 8);
- if (mpi->flags & MP_IMGFLAG_PLANAR) {
- if (mpi->flags & MP_IMGFLAG_SWAPPED) {
- // I420
- mpi->planes[1] = current_image->data
- + current_image->offsets[1];
- mpi->planes[2] = current_image->data
- + current_image->offsets[2];
- mpi->stride[1] = current_image->pitches[1];
- mpi->stride[2] = current_image->pitches[2];
- } else {
- // YV12
- mpi->planes[1] = current_image->data
- + current_image->offsets[2];
- mpi->planes[2] = current_image->data
- + current_image->offsets[1];
- mpi->stride[1] = current_image->pitches[2];
- mpi->stride[2] = current_image->pitches[1];
- }
- }
- mpi->flags |= MP_IMGFLAG_DIRECT;
- mpi->priv = (void *)(size_t)ctx->current_buf;
- return VO_TRUE;
- }
- return VO_FALSE;
-}
-
static int query_format(struct xvctx *ctx, uint32_t format)
{
uint32_t i;
@@ -813,8 +726,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
return (ctx->is_paused = 0);
case VOCTRL_QUERY_FORMAT:
return query_format(ctx, *((uint32_t *) data));
- case VOCTRL_GET_IMAGE:
- return get_image(ctx, data);
case VOCTRL_DRAW_IMAGE:
return draw_image(vo, data);
case VOCTRL_GET_PANSCAN:
diff --git a/libvo/x11_common.c b/libvo/x11_common.c
index 7796d626db..2fae9f480a 100644
--- a/libvo/x11_common.c
+++ b/libvo/x11_common.c
@@ -46,7 +46,7 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
-#include <X11/keysymdef.h>
+#include <X11/keysym.h>
#ifdef CONFIG_XSS
#include <X11/extensions/scrnsaver.h>
@@ -780,12 +780,13 @@ static int check_resize(struct vo *vo)
int vo_x11_check_events(struct vo *vo)
{
struct vo_x11_state *x11 = vo->x11;
+ struct MPOpts *opts = vo->opts;
Display *display = vo->x11->display;
int ret = 0;
XEvent Event;
- if (x11->vo_mouse_autohide && x11->mouse_waiting_hide &&
- (GetTimerMS() - x11->mouse_timer >= 1000)) {
+ if (x11->mouse_waiting_hide && opts->cursor_autohide_delay != -1 &&
+ (GetTimerMS() - x11->mouse_timer >= opts->cursor_autohide_delay)) {
vo_hidecursor(display, x11->window);
x11->mouse_waiting_hide = 0;
}
@@ -846,16 +847,14 @@ int vo_x11_check_events(struct vo *vo)
case MotionNotify:
vo_mouse_movement(vo, Event.xmotion.x, Event.xmotion.y);
- if (x11->vo_mouse_autohide)
- {
+ if (opts->cursor_autohide_delay > -2) {
vo_showcursor(display, x11->window);
x11->mouse_waiting_hide = 1;
x11->mouse_timer = GetTimerMS();
}
break;
case ButtonPress:
- if (x11->vo_mouse_autohide)
- {
+ if (opts->cursor_autohide_delay > -2) {
vo_showcursor(display, x11->window);
x11->mouse_waiting_hide = 1;
x11->mouse_timer = GetTimerMS();
@@ -865,8 +864,7 @@ int vo_x11_check_events(struct vo *vo)
| MP_KEY_DOWN);
break;
case ButtonRelease:
- if (x11->vo_mouse_autohide)
- {
+ if (opts->cursor_autohide_delay > -2) {
vo_showcursor(display, x11->window);
x11->mouse_waiting_hide = 1;
x11->mouse_timer = GetTimerMS();
@@ -1177,7 +1175,6 @@ final:
x11->vo_gc = XCreateGC(mDisplay, x11->window, 0, NULL);
XSync(mDisplay, False);
- x11->vo_mouse_autohide = 1;
vo->event_fd = ConnectionNumber(x11->display);
}
diff --git a/libvo/x11_common.h b/libvo/x11_common.h
index 6ba2780747..14c7e44549 100644
--- a/libvo/x11_common.h
+++ b/libvo/x11_common.h
@@ -48,7 +48,6 @@ struct vo_x11_state {
unsigned long xv_colorkey;
unsigned int xv_port;
- int vo_mouse_autohide;
int wm_type;
int fs_type;
int window_state;
diff --git a/mixer.c b/mixer.c
index 66b69a2e8d..d115dc3e20 100644
--- a/mixer.c
+++ b/mixer.c
@@ -25,11 +25,6 @@
#include "mixer.h"
-char *mixer_device = NULL;
-char *mixer_channel = NULL;
-int soft_vol = 0;
-float soft_vol_max = 110.0;
-
static void internal_setvolume(mixer_t *mixer, float l, float r);
@@ -87,7 +82,7 @@ static void internal_getvolume(mixer_t *mixer, float *l, float *r)
*l = 0;
*r = 0;
if (mixer->ao) {
- if (soft_vol ||
+ if (mixer->softvol ||
CONTROL_OK != ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol))
{
if (!mixer->afilter)
@@ -100,8 +95,8 @@ static void internal_getvolume(mixer_t *mixer, float *l, float *r)
} else {
af_from_dB(2, db_vals, db_vals, 20.0, -200.0, 60.0);
}
- vol.left = (db_vals[0] / (soft_vol_max / 100.0)) * 100.0;
- vol.right = (db_vals[1] / (soft_vol_max / 100.0)) * 100.0;
+ vol.left = (db_vals[0] / (mixer->softvol_max / 100.0)) * 100.0;
+ vol.right = (db_vals[1] / (mixer->softvol_max / 100.0)) * 100.0;
}
*r = vol.right;
*l = vol.left;
@@ -121,7 +116,7 @@ static void internal_setvolume(mixer_t *mixer, float l, float r)
vol.right = r;
vol.left = l;
if (mixer->ao) {
- bool use_softvol = soft_vol;
+ bool use_softvol = mixer->softvol;
if (!use_softvol) {
if (CONTROL_OK != ao_control(mixer->ao, AOCONTROL_SET_VOLUME, &vol))
{
@@ -136,10 +131,11 @@ static void internal_setvolume(mixer_t *mixer, float l, float r)
// af_volume uses values in dB
float db_vals[AF_NCH];
int i;
- db_vals[0] = (l / 100.0) * (soft_vol_max / 100.0);
- db_vals[1] = (r / 100.0) * (soft_vol_max / 100.0);
+ db_vals[0] = (l / 100.0) * (mixer->softvol_max / 100.0);
+ db_vals[1] = (r / 100.0) * (mixer->softvol_max / 100.0);
for (i = 2; i < AF_NCH; i++)
- db_vals[i] = ((l + r) / 100.0) * (soft_vol_max / 100.0) / 2.0;
+ db_vals[i] = ((l + r) / 100.0) * (mixer->softvol_max / 100.0)
+ / 2.0;
af_to_dB(AF_NCH, db_vals, db_vals, 20.0);
if (!af_control_any_rev(mixer->afilter,
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, db_vals))
@@ -225,7 +221,7 @@ void mixer_mute(mixer_t *mixer)
bool mixer_getmuted(mixer_t *mixer)
{
ao_control_vol_t vol = {0};
- if (!soft_vol &&
+ if (!mixer->softvol &&
CONTROL_OK == ao_control(mixer->ao, AOCONTROL_GET_MUTE, &vol))
{
mixer->muted = vol.left == 0.0f || vol.right == 0.0f;
@@ -243,7 +239,7 @@ void mixer_setmuted(mixer_t *mixer, bool mute)
return;
ao_control_vol_t vol;
vol.left = vol.right = mute ? 0.0f : 1.0f;
- mixer->mute_emulation = soft_vol ||
+ mixer->mute_emulation = mixer->softvol ||
CONTROL_OK != ao_control(mixer->ao, AOCONTROL_SET_MUTE, &vol);
if (mixer->mute_emulation) {
// mute is emulated by setting volume to 0
diff --git a/mixer.h b/mixer.h
index 6619783a58..d5af03bef2 100644
--- a/mixer.h
+++ b/mixer.h
@@ -24,17 +24,14 @@
#include "libaf/af.h"
#include "libao2/audio_out.h"
-extern char * mixer_device;
-extern char * mixer_channel;
-extern int soft_vol;
-extern float soft_vol_max;
-
-typedef struct mixer_s {
+typedef struct mixer {
struct ao *ao;
af_stream_t *afilter;
int volstep;
bool muted;
bool mute_emulation;
+ bool softvol;
+ float softvol_max;
float last_l, last_r;
float restore_vol_l, restore_vol_r;
bool restore_volume;
diff --git a/mp_core.h b/mp_core.h
index 26ba1b764f..190b81883f 100644
--- a/mp_core.h
+++ b/mp_core.h
@@ -254,8 +254,7 @@ char *chapter_display_name(struct MPContext *mpctx, int chapter);
char *chapter_name(struct MPContext *mpctx, int chapter);
double chapter_start_time(struct MPContext *mpctx, int chapter);
int get_chapter_count(struct MPContext *mpctx);
-void update_subtitles(struct MPContext *mpctx, double refpts,
- double sub_offset, bool reset);
+void update_subtitles(struct MPContext *mpctx, double refpts, bool reset);
// timeline/tl_matroska.c
diff --git a/mp_msg.c b/mp_msg.c
index eafa6ac001..6ad39a0416 100644
--- a/mp_msg.c
+++ b/mp_msg.c
@@ -339,7 +339,7 @@ char *mp_gtext(const char *string)
* couple of reasons (locale stuff is badly designed and sucks in
* general).
*
- * First setting the locale, especially LC_CTYPE, changes the
+ * First, setting the locale, especially LC_CTYPE, changes the
* behavior of various C functions and we don't want that - we
* want isalpha() for example to always behave like in the C
* locale.
@@ -361,7 +361,7 @@ char *mp_gtext(const char *string)
* affect gettext itself because it supports specifying the
* character set directly with bind_textdomain_codeset()).
*
- * So the only solution (at leat short of trying to work around
+ * So the only solution (at least short of trying to work around
* things possibly producing non-utf-8 output) is to leave all the
* locale variables unset. Note that this means it's not possible
* to get translated output from any libraries we call if they
diff --git a/mplayer.c b/mplayer.c
index 004bbc621a..05bcf26fae 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1229,6 +1229,8 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
if (mpctx->time_frame > 0)
mpctx->last_av_difference +=
mpctx->time_frame * opts->playback_speed;
+ if (a_pos == MP_NOPTS_VALUE || mpctx->video_pts == MP_NOPTS_VALUE)
+ mpctx->last_av_difference = MP_NOPTS_VALUE;
if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50
&& !mpctx->drop_message_shown) {
mp_tmsg(MSGT_AVSYNC, MSGL_WARN, SystemTooSlow);
@@ -1238,9 +1240,6 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
if (opts->quiet)
return;
- if (a_pos == MP_NOPTS_VALUE)
- a_pos = -9; // don't print a huge negative number
-
int width;
char *line;
unsigned pos = 0;
@@ -1258,8 +1257,11 @@ static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
// Audio time
if (mpctx->sh_audio) {
- saddf(line, &pos, width, "A:%6.1f ", a_pos);
- if (!sh_video) {
+ if (a_pos != MP_NOPTS_VALUE)
+ saddf(line, &pos, width, "A:%6.1f ", a_pos);
+ else
+ saddf(line, &pos, width, "A: ??? ");
+ if (!sh_video && a_pos != MP_NOPTS_VALUE) {
float len = get_time_length(mpctx);
saddf(line, &pos, width, "(");
sadd_hhmmssf(line, &pos, width, a_pos);
@@ -1270,13 +1272,22 @@ 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 ", mpctx->video_pts);
+ if (sh_video) {
+ if (mpctx->video_pts != MP_NOPTS_VALUE)
+ saddf(line, &pos, width, "V:%6.1f ", mpctx->video_pts);
+ else
+ saddf(line, &pos, width, "V: ??? ", mpctx->video_pts);
+ }
// A-V sync
- if (mpctx->sh_audio && sh_video)
- saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ",
- mpctx->last_av_difference, mpctx->total_avsync_change);
+ if (mpctx->sh_audio && sh_video) {
+ if (mpctx->last_av_difference != MP_NOPTS_VALUE)
+ saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ",
+ mpctx->last_av_difference, mpctx->total_avsync_change);
+ else
+ saddf(line, &pos, width, "A-V: ??? ct:%7.3f ",
+ mpctx->total_avsync_change);
+ }
// Video stats
if (sh_video)
@@ -1770,7 +1781,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
current_module = "af_preinit";
if (!(mpctx->initialized_flags & INITIALIZED_AO)) {
mpctx->initialized_flags |= INITIALIZED_AO;
- mpctx->ao = ao_create();
+ mpctx->ao = ao_create(opts, mpctx->input);
mpctx->ao->samplerate = force_srate;
mpctx->ao->format = opts->audio_output_format;
}
@@ -1818,6 +1829,8 @@ void reinit_audio_chain(struct MPContext *mpctx)
}
mpctx->mixer.ao = ao;
mpctx->mixer.volstep = volstep;
+ mpctx->mixer.softvol = opts->softvol;
+ mpctx->mixer.softvol_max = opts->softvol_max;
mixer_reinit(&mpctx->mixer);
mpctx->syncing_audio = true;
return;
@@ -1898,13 +1911,14 @@ static bool is_av_sub(int type)
return type == 'b' || type == 'p' || type == 'x';
}
-void update_subtitles(struct MPContext *mpctx, double refpts,
- double sub_offset, bool reset)
+void update_subtitles(struct MPContext *mpctx, double refpts_tl, bool reset)
{
+ mpctx->osd->sub_offset = mpctx->video_offset;
struct MPOpts *opts = &mpctx->opts;
struct sh_video *sh_video = mpctx->sh_video;
struct demux_stream *d_sub = mpctx->d_sub;
- double curpts = refpts + sub_delay;
+ double refpts_s = refpts_tl - mpctx->osd->sub_offset;
+ double curpts_s = refpts_s + sub_delay;
unsigned char *packet = NULL;
int len;
struct sh_sub *sh_sub = d_sub->sh;
@@ -1929,7 +1943,7 @@ void update_subtitles(struct MPContext *mpctx, double refpts,
if (sub_fps == 0)
sub_fps = sh_video ? sh_video->fps : 25;
current_module = "find_sub";
- find_sub(mpctx, mpctx->subdata, curpts *
+ find_sub(mpctx, mpctx->subdata, curpts_s *
(mpctx->subdata->sub_uses_time ? 100. : sub_fps));
if (vo_sub)
mpctx->vo_sub_last = vo_sub;
@@ -1944,13 +1958,13 @@ void update_subtitles(struct MPContext *mpctx, double refpts,
// Vobsub
len = 0;
if (vo_vobsub) {
- if (curpts >= 0) {
- len = vobsub_get_packet(vo_vobsub, curpts,
+ if (curpts_s >= 0) {
+ len = vobsub_get_packet(vo_vobsub, curpts_s,
(void **)&packet, &timestamp);
if (len > 0)
mp_dbg(MSGT_CPLAYER, MSGL_V, "\rVOB sub: len=%d "
"v_pts=%5.3f v_timer=%5.3f sub=%5.3f ts=%d \n",
- len, refpts, sh_video->timer,
+ len, refpts_s, sh_video->timer,
timestamp / 90000.0, timestamp);
}
} else {
@@ -1962,14 +1976,14 @@ void update_subtitles(struct MPContext *mpctx, double refpts,
// d_video->pts which would have been the simplest
// improvement doesn't work because mpeg specific hacks
// in video.c set d_video->pts to 0.
- float x = d_sub->pts - refpts;
+ float x = d_sub->pts - refpts_s;
if (x > -20 && x < 20) // prevent missing subs on pts reset
timestamp = 90000 * d_sub->pts;
else
- timestamp = 90000 * curpts;
+ timestamp = 90000 * curpts_s;
mp_dbg(MSGT_CPLAYER, MSGL_V, "\rDVD sub: len=%d "
"v_pts=%5.3f s_pts=%5.3f ts=%d \n", len,
- refpts, d_sub->pts, timestamp);
+ refpts_s, d_sub->pts, timestamp);
}
}
if (len <= 0 || !packet)
@@ -1995,19 +2009,19 @@ void update_subtitles(struct MPContext *mpctx, double refpts,
ds_get_next_pts(d_sub);
while (d_sub->first) {
- double subpts = ds_get_next_pts(d_sub) + sub_offset;
- if (subpts > curpts) {
+ double subpts_s = ds_get_next_pts(d_sub);
+ if (subpts_s > curpts_s) {
// Libass handled subs can be fed to it in advance
if (!opts->ass_enabled || !is_text_sub(type))
break;
// Try to avoid demuxing whole file at once
- if (d_sub->non_interleaved && subpts > curpts + 1)
+ if (d_sub->non_interleaved && subpts_s > curpts_s + 1)
break;
}
double duration = d_sub->first->duration;
len = ds_get_packet_sub(d_sub, &packet);
if (is_av_sub(type)) {
- int ret = decode_avsub(sh_sub, packet, len, subpts, duration);
+ int ret = decode_avsub(sh_sub, packet, len, subpts_s, duration);
if (ret < 0)
mp_msg(MSGT_SPUDEC, MSGL_WARN, "lavc failed decoding "
"subtitle\n");
@@ -2036,10 +2050,10 @@ void update_subtitles(struct MPContext *mpctx, double refpts,
continue;
}
if (sh_sub && sh_sub->active) {
- sub_decode(sh_sub, mpctx->osd, packet, len, subpts, duration);
+ sub_decode(sh_sub, mpctx->osd, packet, len, subpts_s, duration);
continue;
}
- if (subpts != MP_NOPTS_VALUE) {
+ if (subpts_s != MP_NOPTS_VALUE) {
if (duration < 0)
sub_clear_text(&subs, MP_NOPTS_VALUE);
if (type == 'a') { // ssa/ass subs without libass => convert to plaintext
@@ -2053,21 +2067,21 @@ void update_subtitles(struct MPContext *mpctx, double refpts,
len -= p - packet;
packet = p;
}
- double endpts = MP_NOPTS_VALUE;
- if (subpts != MP_NOPTS_VALUE && duration >= 0)
- endpts = subpts + duration;
- sub_add_text(&subs, packet, len, endpts);
+ double endpts_s = MP_NOPTS_VALUE;
+ if (subpts_s != MP_NOPTS_VALUE && duration >= 0)
+ endpts_s = subpts_s + duration;
+ sub_add_text(&subs, packet, len, endpts_s);
set_osd_subtitle(mpctx, &subs);
}
if (d_sub->non_interleaved)
ds_get_next_pts(d_sub);
}
if (!opts->ass_enabled)
- if (sub_clear_text(&subs, curpts))
+ if (sub_clear_text(&subs, curpts_s))
set_osd_subtitle(mpctx, &subs);
}
if (vo_spudec) {
- spudec_heartbeat(vo_spudec, 90000 * curpts);
+ spudec_heartbeat(vo_spudec, 90000 * curpts_s);
if (spudec_changed(vo_spudec))
vo_osd_changed(OSDTYPE_SPU);
}
@@ -2500,7 +2514,7 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
return decode_audio(sh_audio, &ao->buffer, playsize);
}
-static int fill_audio_out_buffers(struct MPContext *mpctx)
+static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
{
struct MPOpts *opts = &mpctx->opts;
struct ao *ao = mpctx->ao;
@@ -2562,8 +2576,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
t = GetTimer() - t;
tt = t * 0.000001f;
audio_time_usage += tt;
- if (mpctx->timeline && modifiable_audio_format) {
- double endpts = mpctx->timeline[mpctx->timeline_part + 1].start;
+ if (endpts != MP_NOPTS_VALUE && modifiable_audio_format) {
double bytes = (endpts - written_audio_pts(mpctx) + audio_delay)
* ao->bps / opts->playback_speed;
if (playsize > bytes) {
@@ -2605,65 +2618,6 @@ static int fill_audio_out_buffers(struct MPContext *mpctx)
return -partial_fill;
}
-static int sleep_until_near_frame(struct MPContext *mpctx, float *time_frame,
- bool sync_to_audio, float *aq_sleep_time)
-{
- struct MPOpts *opts = &mpctx->opts;
- double audio_limit = 2;
- current_module = "calc_sleep_time";
-
- if (mpctx->restart_playback)
- return 0;
-
- *time_frame -= get_relative_time(mpctx); // reset timer
-
- if (sync_to_audio) {
- float delay = ao_get_delay(mpctx->ao);
- mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "delay=%f\n", delay);
-
- if (opts->autosync) {
- /*
- * Adjust this raw delay value by calculating the expected
- * delay for this frame and generating a new value which is
- * weighted between the two. The higher autosync is, the
- * closer to the delay value gets to that which "-nosound"
- * would have used, and the longer it will take for A/V
- * sync to settle at the right value (but it eventually will.)
- * This settling time is very short for values below 100.
- */
- float predicted = mpctx->delay / opts->playback_speed + *time_frame;
- float difference = delay - predicted;
- delay = predicted + difference / (float)opts->autosync;
- }
-
- *time_frame = delay - mpctx->delay / opts->playback_speed;
-
- // delay = amount of audio buffered in soundcard/driver
- 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".
- // If benchmark is set always output frames as fast as possible
- // without sleeping.
- if (*time_frame < -0.2 || opts->benchmark)
- *time_frame = 0;
- }
-
- double t = *time_frame - mpctx->video_out->flip_queue_offset;
-
- if (t <= 0.05)
- return 0;
-
- 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)
{
struct MPOpts *opts = &mpctx->opts;
@@ -3070,7 +3024,7 @@ static int redraw_osd(struct MPContext *mpctx)
return -1;
if (vo_redraw_frame(mpctx->video_out) < 0)
return -1;
- mpctx->osd->pts = mpctx->video_pts;
+ mpctx->osd->pts = mpctx->video_pts - mpctx->osd->sub_offset;
if (!(sh_video->output_flags & VFCAP_EOSD_FILTER))
vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd);
vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd);
@@ -3086,39 +3040,7 @@ void add_step_frame(struct MPContext *mpctx)
unpause_player(mpctx);
}
-static void pause_loop(struct MPContext *mpctx)
-{
- mp_cmd_t *cmd;
-
- update_pause_message(mpctx);
-
- while ((cmd = mp_input_get_cmd(mpctx->input, 20, 1)) == NULL
- || cmd->id == MP_CMD_SET_MOUSE_POS || cmd->pausing == 4) {
- if (cmd) {
- cmd = mp_input_get_cmd(mpctx->input, 0, 0);
- run_command(mpctx, cmd);
- mp_cmd_free(cmd);
- continue;
- }
- if (mpctx->sh_video && mpctx->video_out)
- vo_check_events(mpctx->video_out);
- update_osd_msg(mpctx);
- int hack = vo_osd_changed(0);
- vo_osd_changed(hack);
- if (hack || mpctx->sh_video && mpctx->video_out->want_redraw)
- break;
- update_pause_message(mpctx);
- }
-}
-
-static void reinit_decoders(struct MPContext *mpctx)
-{
- reinit_video_chain(mpctx);
- reinit_audio_chain(mpctx);
- mp_property_do("sub", M_PROPERTY_SET, &(int){mpctx->global_sub_pos}, mpctx);
-}
-
-static void seek_reset(struct MPContext *mpctx, bool reset_ao)
+static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
{
if (mpctx->sh_video) {
current_module = "seek_video_reset";
@@ -3130,18 +3052,16 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao)
mpctx->sh_video->last_pts = MP_NOPTS_VALUE;
mpctx->delay = 0;
mpctx->time_frame = 0;
- mpctx->restart_playback = true;
// Not all demuxers set d_video->pts during seek, so this value
// (which is used by at least vobsub 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->sh_video->pts, mpctx->video_offset,
- true);
+ update_subtitles(mpctx, mpctx->sh_video->pts, true);
update_teletext(mpctx->sh_video, mpctx->demuxer, 1);
}
- if (mpctx->sh_audio) {
+ if (mpctx->sh_audio && reset_ac) {
current_module = "seek_audio_reset";
resync_audio_stream(mpctx->sh_audio);
if (reset_ao)
@@ -3149,8 +3069,7 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao)
mpctx->ao->buffer.len = mpctx->ao->buffer_playable_size;
mpctx->sh_audio->a_buffer_len = 0;
if (!mpctx->sh_video)
- update_subtitles(mpctx, mpctx->sh_audio->pts,
- mpctx->video_offset, true);
+ update_subtitles(mpctx, mpctx->sh_audio->pts, true);
}
if (vo_vobsub && mpctx->sh_video) {
@@ -3158,6 +3077,7 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao)
vobsub_seek(vo_vobsub, mpctx->sh_video->pts);
}
+ mpctx->restart_playback = true;
mpctx->hrseek_active = false;
mpctx->hrseek_framedrop = false;
mpctx->total_avsync_change = 0;
@@ -3249,13 +3169,19 @@ static int seek(MPContext *mpctx, struct seek_params seek,
if (demuxer_amount == -1) {
mpctx->stop_play = AT_END_OF_FILE;
// Clear audio from current position
- if (mpctx->sh_audio) {
+ if (mpctx->sh_audio && !timeline_fallthrough) {
ao_reset(mpctx->ao);
mpctx->sh_audio->a_buffer_len = 0;
}
return -1;
}
}
+ if (need_reset) {
+ reinit_video_chain(mpctx);
+ mp_property_do("sub", M_PROPERTY_SET, &(int){mpctx->global_sub_pos},
+ mpctx);
+ }
+
int demuxer_style = 0;
switch (seek.type) {
case MPSEEK_FACTOR:
@@ -3272,12 +3198,19 @@ static int seek(MPContext *mpctx, struct seek_params seek,
demuxer_amount -= opts->hr_seek_demuxer_offset;
int seekresult = demux_seek(mpctx->demuxer, demuxer_amount, audio_delay,
demuxer_style);
- if (need_reset)
- reinit_decoders(mpctx);
- if (seekresult == 0)
+ if (seekresult == 0) {
+ if (need_reset) {
+ reinit_audio_chain(mpctx);
+ seek_reset(mpctx, !timeline_fallthrough, false);
+ }
return -1;
+ }
- seek_reset(mpctx, !timeline_fallthrough);
+ if (need_reset)
+ reinit_audio_chain(mpctx);
+ /* If we just reinitialized audio it doesn't need to be reset,
+ * and resetting could lose audio some decoders produce during init. */
+ seek_reset(mpctx, !timeline_fallthrough, !need_reset);
/* Use the target time as "current position" for further relative
* seeks etc until a new video frame has been decoded */
@@ -3368,9 +3301,11 @@ double get_current_time(struct MPContext *mpctx)
struct demuxer *demuxer = mpctx->demuxer;
if (demuxer->stream_pts != MP_NOPTS_VALUE)
return demuxer->stream_pts;
- struct sh_video *sh_video = demuxer->video->sh;
- if (sh_video)
- return mpctx->video_pts;
+ if (mpctx->sh_video) {
+ double pts = mpctx->video_pts;
+ if (pts != MP_NOPTS_VALUE)
+ return pts;
+ }
double apts = playing_audio_pts(mpctx);
if (apts != MP_NOPTS_VALUE)
return apts;
@@ -3463,7 +3398,7 @@ int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts)
int res = demuxer_seek_chapter(mpctx->demuxer, chapter, seek_pts);
if (res >= 0) {
if (*seek_pts == -1)
- seek_reset(mpctx, true);
+ seek_reset(mpctx, true, true);
else {
mpctx->last_chapter_seek = res;
mpctx->last_chapter_pts = *seek_pts;
@@ -3486,8 +3421,20 @@ int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts)
static void run_playloop(struct MPContext *mpctx)
{
struct MPOpts *opts = &mpctx->opts;
- float aq_sleep_time = 0;
bool full_audio_buffers = false;
+ bool audio_left = false, video_left = false;
+ double endpts = end_at.type == END_AT_TIME ? end_at.pos : MP_NOPTS_VALUE;
+ bool end_is_chapter = false;
+ double sleeptime = 0.5;
+ bool was_restart = mpctx->restart_playback;
+
+ if (mpctx->timeline) {
+ double end = mpctx->timeline[mpctx->timeline_part + 1].start;
+ if (endpts == MP_NOPTS_VALUE || end < endpts) {
+ endpts = end;
+ end_is_chapter = true;
+ }
+ }
if (opts->chapterrange[1] > 0) {
int cur_chapter = get_current_chapter(mpctx);
@@ -3501,79 +3448,27 @@ static void run_playloop(struct MPContext *mpctx)
reinit_audio_chain(mpctx);
}
- /*========================== PLAY AUDIO ============================*/
-
- if (!mpctx->sh_video)
- mpctx->restart_playback = false;
+ if (mpctx->step_frames && !mpctx->sh_video) {
+ mpctx->step_frames = 0;
+ pause_player(mpctx);
+ }
if (mpctx->sh_audio && !mpctx->restart_playback) {
- int status = fill_audio_out_buffers(mpctx);
+ int status = fill_audio_out_buffers(mpctx, endpts);
full_audio_buffers = status >= 0 && !mpctx->ao->untimed;
- if (status == -2)
- // at eof, all audio at least written to ao
- if (!mpctx->sh_video)
- mpctx->stop_play = AT_END_OF_FILE;
+ // Not at audio stream EOF yet
+ audio_left = status > -2;
}
-
- if (!mpctx->sh_video) {
- if (mpctx->step_frames) {
- mpctx->step_frames = 0;
- pause_player(mpctx);
- }
- // handle audio-only case:
- double a_pos = 0, a_buf = 0;
- // sh_audio can be NULL due to video stream switching
- // TODO: handle this better
- if (mpctx->sh_audio) {
- a_buf = ao_get_delay(mpctx->ao);
- a_pos = written_audio_pts(mpctx) - mpctx->opts.playback_speed *
- a_buf;
- }
-
- print_status(mpctx, a_pos, false);
-
- update_subtitles(mpctx, a_pos, mpctx->video_offset, false);
- update_osd_msg(mpctx);
- if (end_at.type == END_AT_TIME && end_at.pos < a_pos)
- mpctx->stop_play = AT_END_OF_FILE;
- else if (mpctx->timeline && mpctx->stop_play == AT_END_OF_FILE
- && mpctx->timeline_part + 1 < mpctx->num_timeline_parts
- && mpctx->sh_audio) {
- struct timeline_part *p = mpctx->timeline + mpctx->timeline_part;
- if (!opts->gapless_audio && p->source != (p + 1)->source
- && a_buf > 0.05) {
- mpctx->stop_play = KEEP_PLAYING;
- mp_input_get_cmd(mpctx->input, (a_buf - .05) * 1000, true);
- } else {
- seek(mpctx, (struct seek_params){ .type = MPSEEK_ABSOLUTE,
- .amount = (p + 1)->start },
- true);
- }
- } else if (!mpctx->stop_play) {
- int sleep_time = 100;
- if (mpctx->sh_audio) {
- if (mpctx->ao->untimed)
- sleep_time = 0;
- else if (full_audio_buffers)
- sleep_time = FFMAX(20, a_buf * 1000 - 50);
- else
- sleep_time = 20;
- sleep_time = FFMIN(sleep_time, 100);
- }
- mp_input_get_cmd(mpctx->input, sleep_time, true);
- }
- } else {
-
- /*========================== PLAY VIDEO ============================*/
-
+ double buffered_audio = -1;
+ while (mpctx->sh_video) { // never loops, for "break;" only
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) {
+ video_left = mpctx->video_out->hasframe;
+ if (!mpctx->video_out->frame_loaded
+ && (!mpctx->paused || mpctx->restart_playback)) {
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,
@@ -3582,25 +3477,14 @@ static void run_playloop(struct MPContext *mpctx)
mpctx->stop_play = PT_NEXT_ENTRY;
return;
}
- if (frame_time < 0)
- mpctx->stop_play = AT_END_OF_FILE;
- else if (!mpctx->restart_playback) {
+ video_left = frame_time >= 0;
+ if (endpts != MP_NOPTS_VALUE)
+ video_left &= mpctx->sh_video->pts < endpts;
+ if (video_left && !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 },
- true);
- return;
- }
- }
// ================================================================
@@ -3622,78 +3506,116 @@ static void run_playloop(struct MPContext *mpctx)
}
}
- bool frame_time_remaining = sleep_until_near_frame(mpctx,
- &mpctx->time_frame,
- full_audio_buffers,
- &aq_sleep_time);
+ if (!video_left || (mpctx->paused && !mpctx->restart_playback))
+ break;
+ if (!mpctx->video_out->frame_loaded) {
+ sleeptime = 0;
+ break;
+ }
+
+ mpctx->time_frame -= get_relative_time(mpctx);
+ if (full_audio_buffers && !mpctx->restart_playback) {
+ buffered_audio = ao_get_delay(mpctx->ao);
+ mp_dbg(MSGT_AVSYNC, MSGL_DBG2, "delay=%f\n", buffered_audio);
+
+ if (opts->autosync) {
+ /* Smooth reported playback position from AO by averaging
+ * it with the value expected based on previus value and
+ * time elapsed since then. May help smooth video timing
+ * with audio output that have inaccurate position reporting.
+ * This is badly implemented; the behavior of the smoothing
+ * now undesirably depends on how often this code runs
+ * (mainly depends on video frame rate). */
+ float predicted = (mpctx->delay / opts->playback_speed +
+ mpctx->time_frame);
+ float difference = buffered_audio - predicted;
+ buffered_audio = predicted + difference / opts->autosync;
+ }
+
+ mpctx->time_frame = (buffered_audio -
+ mpctx->delay / opts->playback_speed);
+ } else {
+ /* If we're more than 200 ms behind the right playback
+ * position, don't try to speed up display of following
+ * frames to catch up; continue with default speed from
+ * the current frame instead.
+ * If benchmark is set always output frames immediately
+ * without sleeping.
+ */
+ if (mpctx->time_frame < -0.2 || opts->benchmark)
+ mpctx->time_frame = 0;
+ }
+
+ double vsleep = mpctx->time_frame - mpctx->video_out->flip_queue_offset;
+ if (vsleep > 0.050) {
+ sleeptime = FFMIN(sleeptime, vsleep - 0.040);
+ break;
+ }
+ sleeptime = 0;
//=================== FLIP PAGE (VIDEO BLT): ======================
current_module = "flip_page";
- if (!frame_time_remaining && blit_frame) {
- vo_new_frame_imminent(mpctx->video_out);
- struct sh_video *sh_video = mpctx->sh_video;
- mpctx->video_pts = sh_video->pts;
- update_subtitles(mpctx, sh_video->pts, mpctx->video_offset, false);
- update_teletext(sh_video, mpctx->demuxer, 0);
- update_osd_msg(mpctx);
- struct vf_instance *vf = sh_video->vfilter;
- mpctx->osd->pts = mpctx->video_pts;
- vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd);
- 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 & VFCAP_TIMER))
- mpctx->time_frame = timing_sleep(mpctx, mpctx->time_frame);
- mpctx->time_frame += mpctx->video_out->flip_queue_offset;
-
- unsigned int t2 = GetTimer();
- /* Playing with playback speed it's possible to get pathological
- * cases with mpctx->time_frame negative enough to cause an
- * overflow in pts_us calculation, thus the FFMAX. */
- double time_frame = FFMAX(mpctx->time_frame, -1);
- unsigned int pts_us = mpctx->last_time + 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)
- fill_audio_out_buffers(mpctx);
- mpctx->restart_playback = false;
- mpctx->time_frame = 0;
- get_relative_time(mpctx);
- }
- print_status(mpctx, MP_NOPTS_VALUE, true);
- screenshot_flip(mpctx);
- } else
- print_status(mpctx, MP_NOPTS_VALUE, false);
+ vo_new_frame_imminent(mpctx->video_out);
+ struct sh_video *sh_video = mpctx->sh_video;
+ mpctx->video_pts = sh_video->pts;
+ update_subtitles(mpctx, sh_video->pts, false);
+ update_teletext(sh_video, mpctx->demuxer, 0);
+ update_osd_msg(mpctx);
+ struct vf_instance *vf = sh_video->vfilter;
+ mpctx->osd->pts = mpctx->video_pts - mpctx->osd->sub_offset;
+ vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd);
+ vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd);
+ vo_osd_changed(0);
+
+ mpctx->time_frame -= mpctx->video_out->flip_queue_offset;
+ float aq_sleep_time = mpctx->time_frame;
+ if (mpctx->time_frame > 0.001
+ && !(mpctx->sh_video->output_flags & VFCAP_TIMER))
+ mpctx->time_frame = timing_sleep(mpctx, mpctx->time_frame);
+ mpctx->time_frame += mpctx->video_out->flip_queue_offset;
+
+ unsigned int t2 = GetTimer();
+ /* Playing with playback speed it's possible to get pathological
+ * cases with mpctx->time_frame negative enough to cause an
+ * overflow in pts_us calculation, thus the FFMAX. */
+ double time_frame = FFMAX(mpctx->time_frame, -1);
+ unsigned int pts_us = mpctx->last_time + 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)
+ fill_audio_out_buffers(mpctx, endpts);
+ mpctx->restart_playback = false;
+ mpctx->time_frame = 0;
+ get_relative_time(mpctx);
+ }
+ print_status(mpctx, MP_NOPTS_VALUE, true);
+ screenshot_flip(mpctx);
if (opts->auto_quality > 0) {
current_module = "autoq";
@@ -3706,25 +3628,18 @@ static void run_playloop(struct MPContext *mpctx)
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);
- }
+ if (play_n_frames >= 0) {
+ --play_n_frames;
+ if (play_n_frames <= 0)
+ mpctx->stop_play = PT_NEXT_ENTRY;
}
-
- // 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)
+ if (mpctx->step_frames > 0) {
+ mpctx->step_frames--;
+ if (mpctx->step_frames == 0)
+ pause_player(mpctx);
+ }
+ break;
+ } // video
#ifdef CONFIG_DVDNAV
if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
@@ -3750,48 +3665,116 @@ static void run_playloop(struct MPContext *mpctx)
}
#endif
- //================= Keyboard events, SEEKing ====================
+ if (mpctx->restart_playback && !video_left) {
+ if (mpctx->sh_audio) {
+ int status = fill_audio_out_buffers(mpctx, endpts);
+ full_audio_buffers = status >= 0 && !mpctx->ao->untimed;
+ // Not at audio stream EOF yet
+ audio_left = status > -2;
+ }
+ mpctx->restart_playback = false;
+ }
+ if (mpctx->sh_audio && buffered_audio == -1)
+ buffered_audio = mpctx->paused ? 0 : ao_get_delay(mpctx->ao);
- current_module = "key_events";
+ update_osd_msg(mpctx);
+ if (mpctx->paused)
+ update_pause_message(mpctx);
+ if (!video_left && (!mpctx->paused || was_restart)) {
+ double a_pos = 0;
+ if (mpctx->sh_audio) {
+ a_pos = (written_audio_pts(mpctx) -
+ mpctx->opts.playback_speed * buffered_audio);
+ }
+ print_status(mpctx, a_pos, false);
- 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->sh_video)
+ update_subtitles(mpctx, a_pos, false);
+ }
+
+ /* It's possible for the user to simultaneously switch both audio
+ * and video streams to "disabled" at runtime. Handle this by waiting
+ * rather than immediately stopping playback due to EOF.
+ *
+ * When all audio has been written to output driver, stay in the
+ * main loop handling commands until it has been mostly consumed,
+ * except in the gapless case, where the next file will be started
+ * while audio from the current one still remains to be played.
+ *
+ * We want this check to trigger if we seeked to this position,
+ * but not if we paused at it with audio possibly still buffered in
+ * the AO. There's currently no working way to check buffered audio
+ * inside AO while paused. Thus the "was_restart" check below, which
+ * should trigger after seek only, when we know there's no audio
+ * buffered.
+ */
+ if ((mpctx->sh_audio || mpctx->sh_video) && !audio_left && !video_left
+ && (opts->gapless_audio || buffered_audio < 0.05)
+ && (!mpctx->paused || was_restart)) {
+ if (end_is_chapter) {
+ seek(mpctx, (struct seek_params){
+ .type = MPSEEK_ABSOLUTE,
+ .amount = mpctx->timeline[mpctx->timeline_part+1].start
+ }, true);
+ } else
+ mpctx->stop_play = AT_END_OF_FILE;
+ } else if (!mpctx->stop_play) {
+ double audio_sleep = 9;
+ if (mpctx->sh_audio && !mpctx->paused) {
+ if (mpctx->ao->untimed) {
+ if (!mpctx->sh_video)
+ audio_sleep = 0;
+ } else if (full_audio_buffers) {
+ audio_sleep = buffered_audio - 0.050;
+ // Keep extra safety margin if the buffers are large
+ if (audio_sleep > 0.100)
+ audio_sleep = FFMAX(audio_sleep - 0.200, 0.100);
+ else
+ audio_sleep = FFMAX(audio_sleep, 0.020);
+ } else
+ audio_sleep = 0.020;
}
- bool slow_video = mpctx->sh_video && mpctx->video_out->frame_loaded;
- if (!(mpctx->paused || slow_video) || mpctx->stop_play
- || mpctx->seek.type || mpctx->restart_playback)
- break;
- if (mpctx->sh_video) {
- update_osd_msg(mpctx);
+ sleeptime = FFMIN(sleeptime, audio_sleep);
+ if (sleeptime > 0) {
+ if (!mpctx->sh_video)
+ goto novideo;
int hack = vo_osd_changed(0);
vo_osd_changed(hack);
if (hack || mpctx->video_out->want_redraw) {
if (redraw_osd(mpctx) < 0) {
- if (mpctx->paused)
+ if (mpctx->paused && video_left)
add_step_frame(mpctx);
- break;
+ else
+ goto novideo;
} else
vo_osd_changed(0);
+ } else {
+ novideo:
+ mp_input_get_cmd(mpctx->input, sleeptime * 1000, true);
}
}
- if (!mpctx->paused)
+ }
+
+ //================= Keyboard events, SEEKing ====================
+
+ current_module = "key_events";
+
+ 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;
- pause_loop(mpctx);
}
// handle -sstep
diff --git a/options.h b/options.h
index f667031595..e77384b7f4 100644
--- a/options.h
+++ b/options.h
@@ -6,6 +6,10 @@ typedef struct MPOpts {
char **audio_driver_list;
int fixed_vo;
int vo_ontop;
+ char *mixer_device;
+ char *mixer_channel;
+ int softvol;
+ float softvol_max;
int gapless_audio;
int ao_buffersize;
int screen_size_x;
@@ -24,6 +28,7 @@ typedef struct MPOpts {
int requested_colorspace;
int requested_input_range;
int requested_output_range;
+ int cursor_autohide_delay;
// ranges -100 - 100, 1000 if the vo default should be used
int vo_gamma_gamma;
diff --git a/osdep/macosx_finder_args.c b/osdep/macosx_finder_args.c
deleted file mode 100644
index 6b5ef321f4..0000000000
--- a/osdep/macosx_finder_args.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <Carbon/Carbon.h>
-#include <ApplicationServices/ApplicationServices.h>
-#include <stdio.h>
-
-#include "stream/url.h"
-#include "mp_msg.h"
-#include "m_option.h"
-#include "m_config.h"
-#include "playtree.h"
-#include "macosx_finder_args.h"
-
-static play_tree_t *files=NULL;
-
-static inline void add_entry(play_tree_t **last_parentp, play_tree_t **last_entryp, play_tree_t *entry) {
-
- if(*last_entryp==NULL)
- play_tree_set_child(*last_parentp, entry);
- else
- play_tree_append_entry(*last_entryp, entry);
-
- *last_entryp=entry;
-}
-
-static pascal OSErr AppleEventHandlerProc(const AppleEvent *theAppleEvent, AppleEvent* reply, SInt32 handlerRefcon) {
-OSErr err=errAEEventNotHandled, res=noErr;
-AEDescList docList;
-long itemsInList;
-
- AERemoveEventHandler(kCoreEventClass, kAEOpenDocuments, NULL, FALSE);
- if((res=AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList))==noErr) {
- if((res=AECountItems(&docList, &itemsInList))==noErr) {
- Size currentSize=0;
- int valid=0,i;
- char *parm=NULL;
- play_tree_t *last_entry=NULL;
-
- files=play_tree_new();
- for(i=1;i<=itemsInList;++i) {
-
- for(;;) {
- OSErr e;
- Size actualSize=0;
- AEKeyword keywd;
- DescType returnedType;
-
- if((e=AEGetNthPtr(&docList, i, typeFileURL, &keywd, &returnedType, (Ptr)parm, currentSize, &actualSize))==noErr) {
- if(actualSize>=currentSize) {
- currentSize=actualSize+1;
- parm=realloc(parm, currentSize);
- }
- else {
- parm[actualSize]=0;
- valid=1;
- break;
- }
- }
- else {
- valid=0;
- break;
- }
- }
-
- if(valid) {
- URL_t *url=url_new(parm);
-
- if(url && !strcmp(url->protocol,"file") && !strcmp(url->hostname,"localhost")) {
- play_tree_t *entry=play_tree_new();
-
- url_unescape_string(url->file, url->file);
- play_tree_add_file(entry, url->file);
- add_entry(&files, &last_entry, entry);
- }
-
- url_free(url);
- }
- }
-
- free(parm);
-
- err=noErr;
- }
- else
- mp_msg(MSGT_CFGPARSER, MSGL_ERR, "AECountItems() error %d\n", res);
-
- AEDisposeDesc(&docList);
- }
- else
- mp_msg(MSGT_CFGPARSER, MSGL_ERR, "AEGetParamDesc() error %d\n", res);
-
- QuitApplicationEventLoop();
- return err;
-}
-
-play_tree_t *macosx_finder_args(m_config_t *config, int argc, char **argv) {
-ProcessSerialNumber myPsn;
-char myPsnStr[5+10+1+10+1];
-
- GetCurrentProcess(&myPsn);
- snprintf(myPsnStr, 5+10+1+10+1, "-psn_%u_%u", myPsn.highLongOfPSN, myPsn.lowLongOfPSN);
- myPsnStr[5+10+1+10]=0;
-
- if((argc==2) && !strcmp(myPsnStr, argv[1])) {
- m_config_set_option0(config, "quiet", NULL, false);
- InitCursor();
- AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(AppleEventHandlerProc), 0, FALSE);
- RunApplicationEventLoop();
- }
-
- return files;
-}
diff --git a/osdep/macosx_finder_args.h b/osdep/macosx_finder_args.h
index 4f06a139a6..1f18931712 100644
--- a/osdep/macosx_finder_args.h
+++ b/osdep/macosx_finder_args.h
@@ -1,18 +1,18 @@
/*
- * This file is part of MPlayer.
+ * This file is part of mplayer2.
*
- * MPlayer is free software; you can redistribute it and/or modify
+ * mplayer2 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * MPlayer is distributed in the hope that it will be useful,
+ * mplayer2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * with mplayer2; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
diff --git a/osdep/macosx_finder_args.m b/osdep/macosx_finder_args.m
new file mode 100644
index 0000000000..b006f11a79
--- /dev/null
+++ b/osdep/macosx_finder_args.m
@@ -0,0 +1,95 @@
+/*
+ * This file is part of mplayer2.
+ *
+ * mplayer2 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mplayer2 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mplayer2; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <ApplicationServices/ApplicationServices.h>
+#include <stdio.h>
+#include "macosx_finder_args.h"
+
+static play_tree_t *files = NULL;
+
+void macosx_wait_fileopen_events(void);
+void macosx_redirect_output_to_logfile(const char *filename);
+bool psn_matches_current_process(char *psn_arg_to_check);
+
+@interface FileOpenDelegate : NSObject
+- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames;
+@end
+
+@implementation FileOpenDelegate
+- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
+{
+ files = play_tree_new();
+ play_tree_t *last_entry = nil;
+ for (NSString *filename in filenames) {
+ play_tree_t *entry = play_tree_new();
+ play_tree_add_file(entry, [filename UTF8String]);
+
+ if (last_entry)
+ play_tree_append_entry(files, entry);
+ else
+ play_tree_set_child(files, entry);
+
+ last_entry = entry;
+ }
+ [NSApp stop:nil]; // stop the runloop (give back control to mplayer2 code)
+}
+@end
+
+void macosx_wait_fileopen_events()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSApp = [NSApplication sharedApplication];
+ [NSApp setDelegate: [[[FileOpenDelegate alloc] init] autorelease]];
+ [NSApp run]; // block until we recive the fileopen events
+ [pool release];
+}
+
+void macosx_redirect_output_to_logfile(const char *filename)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSString *log_path = [NSHomeDirectory() stringByAppendingPathComponent:
+ [@"Library/Logs/" stringByAppendingFormat:@"%s.log", filename]];
+ freopen([log_path fileSystemRepresentation], "a", stdout);
+ freopen([log_path fileSystemRepresentation], "a", stderr);
+ [pool release];
+}
+
+bool psn_matches_current_process(char *psn_arg_to_check)
+{
+ ProcessSerialNumber psn;
+ char psn_arg[5+10+1+10+1];
+
+ GetCurrentProcess(&psn);
+ snprintf(psn_arg, 5+10+1+10+1, "-psn_%u_%u",
+ psn.highLongOfPSN, psn.lowLongOfPSN);
+ psn_arg[5+10+1+10]=0;
+
+ return strcmp(psn_arg, psn_arg_to_check) == 0;
+}
+
+play_tree_t *macosx_finder_args(m_config_t *config, int argc, char **argv)
+{
+ if (argc==2 && psn_matches_current_process(argv[1])) {
+ macosx_redirect_output_to_logfile("mplayer2");
+ m_config_set_option0(config, "quiet", NULL, false);
+ macosx_wait_fileopen_events();
+ }
+
+ return files;
+}
diff --git a/stream/stream_vstream.c b/stream/stream_vstream.c
index 3bc096f71b..380b682c46 100644
--- a/stream/stream_vstream.c
+++ b/stream/stream_vstream.c
@@ -56,7 +56,7 @@ void vstream_error(const char *format, ...) {
va_start(va, format);
vsnprintf(buf, 1024, format, va);
va_end(va);
- mp_msg(MSGT_STREAM, MSGL_ERR, buf);
+ mp_msg(MSGT_STREAM, MSGL_ERR, "%s", buf);
}
static struct stream_priv_s {
@@ -152,7 +152,8 @@ static int open_s(stream_t *stream, int mode, void* opts, int* file_format) {
stream->start_pos = 0;
stream->end_pos = vstream_streamsize();
- mp_msg(MSGT_OPEN, MSGL_DBG2, "Tivo stream size is %d\n", stream->end_pos);
+ mp_msg(MSGT_OPEN, MSGL_DBG2, "Tivo stream size is %lld\n",
+ (long long)stream->end_pos);
stream->priv = p;
stream->fill_buffer = fill_buffer;
diff --git a/sub/sub.h b/sub/sub.h
index 2f8c4e0ffc..081834e3bb 100644
--- a/sub/sub.h
+++ b/sub/sub.h
@@ -76,6 +76,7 @@ struct osd_state {
struct font_desc *sub_font;
struct ass_track *ass_track;
double pts;
+ double sub_offset;
bool ass_track_changed;
bool vsfilter_aspect;
};