From f01744ac4e1da514aedbb51e6fad42fdb308937e Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 2 Oct 2013 01:15:59 +0200 Subject: core: add --force-window This commit adds the --force-window option, which will cause mpv always to create a window when started. This can be useful when pretending that mpv is a GUI application (which it isn't, but users pretend anyway), and playing audio files would run mpv in the background without giving a window to control it. This doesn't actually create the window immediately: it only does so only after initializing playback and when it is clear that there won't be any actual video. This could be a problem when starting slow or completely stuck network streams (mpv would remain frozen in the background), or if video initialization somehow is stuck forever in an in-between state (like when the decoder doesn't output a video frame, but doesn't return an error either). Well, we can pretend only so much that mpv is a GUI application. --- DOCS/man/en/options.rst | 14 ++++++++ mpvcore/mplayer.c | 91 +++++++++++++++++++++++++++++++++++++++++-------- mpvcore/options.c | 1 + mpvcore/options.h | 1 + mpvcore/screenshot.c | 6 ++-- video/decode/vd_lavc.c | 1 - video/out/vo.c | 5 +++ video/out/vo.h | 1 + 8 files changed, 103 insertions(+), 17 deletions(-) diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 9230529d54..cc0b7a4db2 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -804,6 +804,20 @@ depending on GPU drivers and hardware. For other VOs, this just makes rendering slower. +``--force-window`` + Create a video output window even if there is no video. This can be useful + when pretending that mpv is a GUI application. Currently, the window + always has the size 640x480, and is subject to ``--geometry``, + ``--autofit``, and similar options. + + .. warning:: + + The window is created only after initialization (to make sure default + window placement still works if the video size is different from the + ``--force-window`` default window size). This can be a problem if + initialization doesn't work perfectly, such as when opening URLs with + bad network connection, or opening broken video files. + ``--force-window-position`` Forcefully move mpv's video output window to default location whenever there is a change in video parameters, video stream or file. This used to diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c index 280cc87f3e..98af9d4e37 100644 --- a/mpvcore/mplayer.c +++ b/mpvcore/mplayer.c @@ -1556,7 +1556,7 @@ static void update_osd_msg(struct MPContext *mpctx) // Look if we have a msg mp_osd_msg_t *msg = get_osd_msg(mpctx); if (msg && !msg->show_position) { - if (mpctx->sh_video && opts->term_osd != 1) { + if (mpctx->video_out && opts->term_osd != 1) { osd_set_text(osd, msg->msg); } else if (opts->term_osd) { if (strcmp(mpctx->terminal_osd_text, msg->msg)) { @@ -1576,7 +1576,7 @@ static void update_osd_msg(struct MPContext *mpctx) if (msg && msg->show_position) osd_level = 3; - if (mpctx->sh_video && opts->term_osd != 1) { + if (mpctx->video_out && opts->term_osd != 1) { // fallback on the timer char *text = NULL; @@ -2031,8 +2031,10 @@ void mp_switch_track(struct MPContext *mpctx, enum stream_type type, return; if (type == STREAM_VIDEO) { - uninit_player(mpctx, INITIALIZED_VCODEC | - (mpctx->opts->fixed_vo && track ? 0 : INITIALIZED_VO)); + int uninit = INITIALIZED_VCODEC; + if (!mpctx->opts->force_vo) + uninit |= mpctx->opts->fixed_vo && track ? 0 : INITIALIZED_VO; + uninit_player(mpctx, uninit); } else if (type == STREAM_AUDIO) { uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC); } else if (type == STREAM_SUB) { @@ -2380,7 +2382,8 @@ int reinit_video_chain(struct MPContext *mpctx) init_demux_stream(mpctx, STREAM_VIDEO); sh_video_t *sh_video = mpctx->sh_video; if (!sh_video) { - uninit_player(mpctx, INITIALIZED_VO); + if (!opts->force_vo) + uninit_player(mpctx, INITIALIZED_VO); goto no_video; } @@ -2453,7 +2456,8 @@ int reinit_video_chain(struct MPContext *mpctx) return 1; err_out: - uninit_player(mpctx, INITIALIZED_VO); + if (!opts->force_vo) + uninit_player(mpctx, INITIALIZED_VO); cleanup_demux_stream(mpctx, STREAM_VIDEO); no_video: mpctx->current_track[STREAM_VIDEO] = NULL; @@ -3528,6 +3532,41 @@ static void handle_keep_open(struct MPContext *mpctx) } } +// Execute a forceful refresh of the VO window, if it hasn't had a valid frame +// for a while. The problem is that a VO with no valid frame (vo->hasframe==0) +// doesn't redraw video and doesn't OSD interaction. So screw it, hard. +static void handle_force_window(struct MPContext *mpctx) +{ + // Don't interfere with real video playback + if (mpctx->sh_video) + return; + + struct vo *vo = mpctx->video_out; + if (!vo) + return; + + if (!vo->config_ok) { + MP_INFO(mpctx, "Creating non-video VO window.\n"); + // Pick whatever works + int config_format = 0; + for (int fmt = IMGFMT_START; fmt < IMGFMT_END; fmt++) { + if (vo->driver->query_format(vo, fmt)) { + config_format = fmt; + break; + } + } + int w = 640; + int h = 480; + struct mp_image_params p = { + .imgfmt = config_format, + .w = w, .h = h, + .d_w = w, .d_h = h, + }; + vo_reconfig(vo, &p, 0); + redraw_osd(mpctx); + } +} + static double get_wakeup_period(struct MPContext *mpctx) { /* Even if we can immediately wake up in response to most input events, @@ -3593,6 +3632,11 @@ static void run_playloop(struct MPContext *mpctx) audio_left = status > -2; } + if (mpctx->video_out) { + vo_check_events(mpctx->video_out); + handle_cursor_autohide(mpctx); + } + double buffered_audio = -1; while (mpctx->sh_video) { // never loops, for "break;" only struct vo *vo = mpctx->video_out; @@ -3606,12 +3650,16 @@ static void run_playloop(struct MPContext *mpctx) mp_tmsg(MSGT_CPLAYER, MSGL_FATAL, "\nFATAL: Could not initialize video filters (-vf) " "or video output (-vo).\n"); - uninit_player(mpctx, INITIALIZED_VCODEC | INITIALIZED_VO); + int uninit = INITIALIZED_VCODEC; + if (!opts->force_vo) + uninit |= INITIALIZED_VO; + uninit_player(mpctx, uninit); cleanup_demux_stream(mpctx, STREAM_VIDEO); mpctx->current_track[STREAM_VIDEO] = NULL; if (!mpctx->current_track[STREAM_AUDIO]) mpctx->stop_play = PT_NEXT_ENTRY; mpctx->error_playing = true; + handle_force_window(mpctx); break; } video_left = frame_time >= 0; @@ -3628,11 +3676,6 @@ static void run_playloop(struct MPContext *mpctx) if (endpts != MP_NOPTS_VALUE) video_left &= mpctx->sh_video->pts < endpts; - // ================================================================ - vo_check_events(vo); - - handle_cursor_autohide(mpctx); - handle_heartbeat_cmd(mpctx); if (!video_left || (mpctx->paused && !mpctx->restart_playback)) @@ -3857,7 +3900,7 @@ static void run_playloop(struct MPContext *mpctx) audio_sleep = 0.020; } sleeptime = FFMIN(sleeptime, audio_sleep); - if (sleeptime > 0 && mpctx->sh_video) { + if (sleeptime > 0 && mpctx->video_out && mpctx->video_out->config_ok) { bool want_redraw = vo_get_want_redraw(mpctx->video_out); if (mpctx->video_out->driver->draw_osd) want_redraw |= mpctx->osd->want_redraw; @@ -3888,6 +3931,8 @@ static void run_playloop(struct MPContext *mpctx) handle_keep_open(mpctx); + handle_force_window(mpctx); + execute_queued_seek(mpctx); } @@ -4227,7 +4272,11 @@ static void idle_loop(struct MPContext *mpctx) while (mpctx->opts->player_idle_mode && !mpctx->playlist->current && mpctx->stop_play != PT_QUIT) { - uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_VO); + int uninit = INITIALIZED_AO; + if (!mpctx->opts->force_vo) + uninit |= INITIALIZED_VO; + uninit_player(mpctx, uninit); + handle_force_window(mpctx); mp_cmd_t *cmd; while (!(cmd = mp_input_get_cmd(mpctx->input, get_wakeup_period(mpctx) * 1000, @@ -4925,6 +4974,7 @@ static int mpv_main(int argc, char *argv[]) m_config_set_option0(mpctx->mconfig, "vo", "lavc"); m_config_set_option0(mpctx->mconfig, "ao", "lavc"); m_config_set_option0(mpctx->mconfig, "fixed-vo", "yes"); + m_config_set_option0(mpctx->mconfig, "force-window", "no"); m_config_set_option0(mpctx->mconfig, "gapless-audio", "yes"); mp_input_enable_section(mpctx->input, "encode", MP_INPUT_EXCLUSIVE); } @@ -4936,6 +4986,19 @@ static int mpv_main(int argc, char *argv[]) mpctx->osd = osd_create(opts, mpctx->ass_library); + if (opts->force_vo) { + opts->fixed_vo = 1; + mpctx->video_out = init_best_video_out(mpctx->global, mpctx->input, + mpctx->encode_lavc_ctx); + if (!mpctx->video_out) { + mp_tmsg(MSGT_CPLAYER, MSGL_FATAL, "Error opening/initializing " + "the selected video_out (-vo) device.\n"); + exit_player(mpctx, EXIT_ERROR); + } + mpctx->mouse_cursor_visible = true; + mpctx->initialized_flags |= INITIALIZED_VO; + } + #ifdef CONFIG_LUA // Lua user scripts can call arbitrary functions. Load them at a point // where this is safe. diff --git a/mpvcore/options.c b/mpvcore/options.c index 234d8646bd..b0988bd6e2 100644 --- a/mpvcore/options.c +++ b/mpvcore/options.c @@ -567,6 +567,7 @@ const m_option_t mp_opts[] = { OPT_SETTINGSLIST("vo", vo.video_driver_list, 0, &vo_obj_list), OPT_SETTINGSLIST("ao", audio_driver_list, 0, &ao_obj_list), OPT_FLAG("fixed-vo", fixed_vo, CONF_GLOBAL), + OPT_FLAG("force-window", force_vo, CONF_GLOBAL), OPT_FLAG("ontop", vo.ontop, 0), OPT_FLAG("border", vo.border, 0), diff --git a/mpvcore/options.h b/mpvcore/options.h index fb88456ac9..0f3fa51549 100644 --- a/mpvcore/options.h +++ b/mpvcore/options.h @@ -50,6 +50,7 @@ typedef struct MPOpts { struct m_obj_settings *audio_driver_list; int fixed_vo; + int force_vo; int softvol; float mixer_init_volume; int mixer_init_mute; diff --git a/mpvcore/screenshot.c b/mpvcore/screenshot.c index 161bfac1e5..181292474b 100644 --- a/mpvcore/screenshot.c +++ b/mpvcore/screenshot.c @@ -316,8 +316,10 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode) struct voctrl_screenshot_args args = { .full_window = (mode == MODE_FULL_WINDOW) }; - struct vf_instance *vfilter = mpctx->sh_video->vfilter; - vfilter->control(vfilter, VFCTRL_SCREENSHOT, &args); + if (mpctx->sh_video && mpctx->sh_video->vfilter) { + struct vf_instance *vfilter = mpctx->sh_video->vfilter; + vfilter->control(vfilter, VFCTRL_SCREENSHOT, &args); + } if (!args.out_image) vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args); diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 86c1c92541..6f395ea843 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -778,7 +778,6 @@ static struct mp_image *decode_with_fallback(struct sh_video *sh, // Failed hardware decoding? Try again in software. if (ctx->software_fallback_decoder) { uninit_avctx(sh); - sh->vf_initialized = 0; mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Error using hardware " "decoding, falling back to software decoding.\n"); const char *decoder = ctx->software_fallback_decoder; diff --git a/video/out/vo.c b/video/out/vo.c index a069c442df..0dc60a558d 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -406,6 +406,9 @@ int vo_reconfig(struct vo *vo, struct mp_image_params *params, int flags) vo->dwidth = d_width; vo->dheight = d_height; + talloc_free(vo->params); + vo->params = NULL; + struct mp_image_params p2 = *params; int ret; @@ -419,6 +422,8 @@ int vo_reconfig(struct vo *vo, struct mp_image_params *params, int flags) } vo->config_ok = (ret >= 0); vo->config_count += vo->config_ok; + if (vo->config_ok) + vo->params = talloc_memdup(vo, &p2, sizeof(p2)); if (vo->registered_fd == -1 && vo->event_fd != -1 && vo->config_ok) { mp_input_add_key_fd(vo->input_ctx, vo->event_fd, 1, event_fd_callback, NULL, vo); diff --git a/video/out/vo.h b/video/out/vo.h index 50e83d2809..3b6adddb0c 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -238,6 +238,7 @@ struct vo { struct mp_log *log; // Using e.g. "[vo/vdpau]" as prefix int config_ok; // Last config call was successful? int config_count; // Total number of successful config calls + struct mp_image_params *params; // Configured parameters (as in vo_reconfig) bool probing; -- cgit v1.2.3