Skip to content

Commit

Permalink
Merge branch 'mpv-player:master' into plex-htpc-hdr-patches
Browse files Browse the repository at this point in the history
  • Loading branch information
mitzsch authored Jul 23, 2023
2 parents fae0b3a + e8126e5 commit 2839bf1
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 46 deletions.
3 changes: 1 addition & 2 deletions DOCS/man/input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,7 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
behavior depends on the selected video output.
<window>
Save the contents of the mpv window. Typically scaled, with OSD and
subtitles. The exact behavior depends on the selected video output, and
if no support is available, this will act like ``video``.
subtitles. The exact behavior depends on the selected video output.
<each-frame>
Take a screenshot each frame. Issue this command again to stop taking
screenshots. Note that you should disable frame-dropping when using
Expand Down
9 changes: 5 additions & 4 deletions DOCS/man/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4517,17 +4517,18 @@ Screenshot
``--screenshot-sw=<yes|no>``
Whether to use software rendering for screenshots (default: no).

If set to no, the screenshot will be rendered by the current VO if possible
(only vo_gpu currently). The advantage is that this will (probably) always
If set to no, the screenshot will be rendered by the current VO (only vo_gpu
or vo_gpu_next currently). The advantage is that this will (probably) always
show up as in the video window, because the same code is used for rendering.
But since the renderer needs to be reinitialized, this can be slow and
interrupt playback. (Unless the ``window`` mode is used with the
``screenshot`` command.)
interrupt playback.

If set to yes, the software scaler is used to convert the video to RGB (or
whatever the target screenshot requires). In this case, conversion will
run in a separate thread and will probably not interrupt playback. The
software renderer may lack some capabilities, such as HDR rendering.
If ``window`` mode is used, the image will also be scaled in software
which may not accurately reflect the actual visible result.

Software Scaler
---------------
Expand Down
8 changes: 6 additions & 2 deletions DOCS/man/vo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,12 @@ Available video output drivers are:
or VA API hardware decoding. The driver is designed to avoid any GPU to CPU copies,
and to perform scaling and color space conversion using fixed-function hardware,
if available, rather than GPU shaders. This frees up GPU resources for other tasks.
Currently this driver is experimental and only works with the ``--hwdec=vaapi``
or ``hwdec=drm`` drivers. Supported compositors : Weston and Sway.
It is highly recommended to use this VO with the appropriate ``--hwdec`` option such
as ``auto-safe``. It can still work in some circumstances without ``--hwdec`` due to
mpv's internal conversion filters, but this is not recommended as it's a needless
extra step. Correct output depends on support from your GPU, drivers, and compositor.
Weston and wlroots-based compositors like Sway and Intel GPUs are known to generally
work.

``vaapi``
Intel VA API video output driver with support for hardware decoding. Note
Expand Down
2 changes: 1 addition & 1 deletion audio/out/ao_pipewire.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ const struct ao_driver audio_out_pipewire = {
.loop = NULL,
.stream = NULL,
.init_state = INIT_STATE_NONE,
.options.buffer_msec = 20,
.options.buffer_msec = 0,
.options.volume_mode = VOLUME_MODE_CHANNEL,
},
.options_prefix = "pipewire",
Expand Down
1 change: 1 addition & 0 deletions filters/f_decoder_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ enum dec_ctrl {
VDCTRL_GET_BFRAMES,
// framedrop mode: 0=none, 1=standard, 2=hrseek
VDCTRL_SET_FRAMEDROP,
VDCTRL_CHECK_FORCED_EOF,
};

int mp_decoder_wrapper_control(struct mp_decoder_wrapper *d,
Expand Down
15 changes: 13 additions & 2 deletions osdep/terminal-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,12 +415,23 @@ static void *terminal_thread(void *ptr)
{ .events = POLLIN, .fd = death_pipe[0] },
{ .events = POLLIN, .fd = tty_in }
};
int r = polldev(fds, stdin_ok ? 2 : 1, buf.len ? ESC_TIMEOUT : INPUT_TIMEOUT);
/*
* if the process isn't in foreground process group, then on macos
* polldev() doesn't rest and gets into 100% cpu usage (see issue #11795)
* with read() returning EIO. but we shouldn't quit on EIO either since
* the process might be foregrounded later.
*
* so just avoid poll-ing tty_in when we know the process is not in the
* foreground. there's a small race window, but the timeout will take
* care of it so it's fine.
*/
bool is_fg = tcgetpgrp(tty_in) == getpgrp();
int r = polldev(fds, stdin_ok && is_fg ? 2 : 1, buf.len ? ESC_TIMEOUT : INPUT_TIMEOUT);
if (fds[0].revents)
break;
if (fds[1].revents) {
int retval = read(tty_in, &buf.b[buf.len], BUF_LEN - buf.len);
if (!retval || (retval == -1 && errno != EINTR && errno != EAGAIN))
if (!retval || (retval == -1 && errno != EINTR && errno != EAGAIN && errno != EIO))
break; // EOF/closed
if (retval > 0) {
buf.len += retval;
Expand Down
13 changes: 5 additions & 8 deletions player/lua/osc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1142,9 +1142,8 @@ function window_controls(topbar)
-- deadzone below window controls
local sh_area_y0, sh_area_y1
sh_area_y0 = user_opts.barmargin
sh_area_y1 = (wc_geo.y + (wc_geo.h / 2)) +
get_align(1 - (2 * user_opts.deadzonesize),
osc_param.playresy - (wc_geo.y + (wc_geo.h / 2)), 0, 0)
sh_area_y1 = wc_geo.y + get_align(1 - (2 * user_opts.deadzonesize),
osc_param.playresy - wc_geo.y, 0, 0)
add_area("showhide_wc", wc_geo.x, sh_area_y0, wc_geo.w, sh_area_y1)

if topbar then
Expand Down Expand Up @@ -1532,13 +1531,11 @@ function bar_layout(direction)
if direction > 0 then
-- deadzone below OSC
sh_area_y0 = user_opts.barmargin
sh_area_y1 = (osc_geo.y + (osc_geo.h / 2)) +
get_align(1 - (2*user_opts.deadzonesize),
osc_param.playresy - (osc_geo.y + (osc_geo.h / 2)), 0, 0)
sh_area_y1 = osc_geo.y + get_align(1 - (2 * user_opts.deadzonesize),
osc_param.playresy - osc_geo.y, 0, 0)
else
-- deadzone above OSC
sh_area_y0 = get_align(-1 + (2*user_opts.deadzonesize),
osc_geo.y - (osc_geo.h / 2), 0, 0)
sh_area_y0 = get_align(-1 + (2 * user_opts.deadzonesize), osc_geo.y, 0, 0)
sh_area_y1 = osc_param.playresy - user_opts.barmargin
end
add_area("showhide", 0, sh_area_y0, osc_param.playresx, sh_area_y1)
Expand Down
66 changes: 47 additions & 19 deletions player/screenshot.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,19 @@ static char *gen_fname(struct mp_cmd_ctx *cmd, const char *file_ext)
}
}

static void add_subs(struct MPContext *mpctx, struct mp_image *image)
static void add_osd(struct MPContext *mpctx, struct mp_image *image, int mode)
{
struct mp_osd_res res = osd_res_from_image_params(&image->params);
osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
OSD_DRAW_SUB_ONLY, image);
bool window = mode == MODE_FULL_WINDOW;
struct mp_osd_res res = window ? osd_get_vo_res(mpctx->video_out->osd) :
osd_res_from_image_params(&image->params);
if (mode == MODE_SUBTITLES || window) {
osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
OSD_DRAW_SUB_ONLY, image);
}
if (window) {
osd_draw_on_image(mpctx->osd, res, mpctx->video_pts,
OSD_DRAW_OSD_ONLY, image);
}
}

static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
Expand All @@ -338,45 +346,65 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode,
const struct image_writer_opts *imgopts = mpctx->opts->screenshot_image_opts;
if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd))
mode = 0;
bool need_add_subs = mode == MODE_SUBTITLES;

if (!mpctx->video_out || !mpctx->video_out->config_ok)
return NULL;

vo_wait_frame(mpctx->video_out); // important for each-frame mode

bool use_sw = mpctx->opts->screenshot_sw;
bool window = mode == MODE_FULL_WINDOW;
struct voctrl_screenshot ctrl = {
.scaled = mode == MODE_FULL_WINDOW,
.scaled = window,
.subs = mode != 0,
.osd = mode == MODE_FULL_WINDOW,
.osd = window,
.high_bit_depth = high_depth && imgopts->high_bit_depth,
.native_csp = image_writer_flexible_csp(imgopts),
};
if (!mpctx->opts->screenshot_sw)
if (!use_sw)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &ctrl);
image = ctrl.res;
if (image)
need_add_subs = false;

if (!image && mode != MODE_FULL_WINDOW)
image = vo_get_current_frame(mpctx->video_out);
if (!image) {
if (!use_sw && !image && window)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT_WIN, &image);
mode = MODE_FULL_WINDOW;

if (!image) {
use_sw = true;
MP_VERBOSE(mpctx->screenshot_ctx, "Falling back to software screenshot.\n");
image = vo_get_current_frame(mpctx->video_out);
}
if (!image)
return NULL;

if (image->fmt.flags & MP_IMGFLAG_HWACCEL) {
// vo_get_current_frame() can return a hardware frame, which we have to download first.
if (image && image->fmt.flags & MP_IMGFLAG_HWACCEL) {
struct mp_image *nimage = mp_image_hw_download(image, NULL);
talloc_free(image);
if (!nimage)
return NULL;
image = nimage;
}

if (need_add_subs)
add_subs(mpctx, image);
if (use_sw && image && window) {
struct mp_osd_res res = osd_get_vo_res(mpctx->video_out->osd);
struct mp_osd_res image_res = osd_res_from_image_params(&image->params);
if (!osd_res_equals(res, image_res)) {
struct mp_image *nimage = mp_image_alloc(image->imgfmt, res.w, res.h);
if (!nimage) {
talloc_free(image);
return NULL;
}
struct mp_sws_context *sws = mp_sws_alloc(NULL);
mp_sws_scale(sws, nimage, image);
talloc_free(image);
talloc_free(sws);
image = nimage;
}
}

if (!image)
return NULL;

if (use_sw && mode != 0)
add_osd(mpctx, image, mode);
mp_image_params_guess_csp(&image->params);
return image;
}
Expand Down
15 changes: 15 additions & 0 deletions player/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,16 @@ static bool check_for_hwdec_fallback(struct MPContext *mpctx)
return true;
}

static bool check_for_forced_eof(struct MPContext *mpctx)
{
struct vo_chain *vo_c = mpctx->vo_chain;
struct mp_decoder_wrapper *dec = vo_c->track->dec;

bool forced_eof = false;
mp_decoder_wrapper_control(dec, VDCTRL_CHECK_FORCED_EOF, &forced_eof);
return forced_eof;
}

/* Update avsync before a new video frame is displayed. Actually, this can be
* called arbitrarily often before the actual display.
* This adjusts the time of the next video frame */
Expand Down Expand Up @@ -1041,6 +1051,11 @@ void write_video(struct MPContext *mpctx)
if (r == VD_EOF) {
if (check_for_hwdec_fallback(mpctx))
return;
if (check_for_forced_eof(mpctx)) {
uninit_video_chain(mpctx);
handle_force_window(mpctx, true);
return;
}
if (vo_c->filter->failed_output_conversion)
goto error;

Expand Down
16 changes: 14 additions & 2 deletions video/decode/vd_lavc.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ typedef struct lavc_ctx {
const char *decoder;
bool hwdec_failed;
bool hwdec_notified;
bool force_eof;

bool intra_only;
int framedrop_flags;
Expand Down Expand Up @@ -589,7 +590,14 @@ static void select_and_set_hwdec(struct mp_filter *vd)
MP_VERBOSE(vd, "Using underlying hw-decoder '%s'\n",
ctx->hwdec.codec->name);
} else {
MP_VERBOSE(vd, "Using software decoding.\n");
// If software fallback is disabled and we get here, all hwdec must
// have failed. Tell the ctx to always force an eof.
if (ctx->opts->software_fallback == INT_MAX) {
MP_WARN(ctx, "Software decoding fallback is disabled.\n");
ctx->force_eof = true;
} else {
MP_VERBOSE(vd, "Using software decoding.\n");
}
}
}

Expand Down Expand Up @@ -1167,7 +1175,7 @@ static int decode_frame(struct mp_filter *vd)
vd_ffmpeg_ctx *ctx = vd->priv;
AVCodecContext *avctx = ctx->avctx;

if (!avctx)
if (!avctx || ctx->force_eof)
return AVERROR_EOF;

prepare_decoding(vd);
Expand Down Expand Up @@ -1317,6 +1325,10 @@ static int control(struct mp_filter *vd, enum dec_ctrl cmd, void *arg)
case VDCTRL_SET_FRAMEDROP:
ctx->framedrop_flags = *(int *)arg;
return CONTROL_TRUE;
case VDCTRL_CHECK_FORCED_EOF: {
*(bool *)arg = ctx->force_eof;
return CONTROL_TRUE;
}
case VDCTRL_GET_BFRAMES: {
AVCodecContext *avctx = ctx->avctx;
if (!avctx)
Expand Down
8 changes: 7 additions & 1 deletion video/out/vo_dmabuf_wayland.c
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,11 @@ static int reconfig(struct vo *vo, struct mp_image *img)
{
struct priv *p = vo->priv;

// If we have a supported format but no hw_subfmt, this
// is probably handle_force_window. Consider it valid.
if (is_supported_fmt(img->params.imgfmt) && img->params.hw_subfmt == IMGFMT_NONE)
goto done;

if (!drm_format_check(vo, img)) {
MP_ERR(vo, "Unable to get drm format from hardware decoding!\n");
return VO_ERROR;
Expand All @@ -659,6 +664,7 @@ static int reconfig(struct vo *vo, struct mp_image *img)
return VO_ERROR;
}

done:
if (!vo_wayland_reconfig(vo))
return VO_ERROR;

Expand Down Expand Up @@ -806,7 +812,7 @@ static int preinit(struct vo *vo)
}

if (p->hwdec_type == HWDEC_NONE) {
MP_ERR(vo, "No valid hardware decoding driver could be loaded!");
MP_ERR(vo, "No valid hardware decoding driver could be loaded!\n");
goto err;
}

Expand Down
5 changes: 0 additions & 5 deletions video/out/vo_drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,12 +440,7 @@ static int query_format(struct vo *vo, int format)

static int control(struct vo *vo, uint32_t request, void *arg)
{
struct priv *p = vo->priv;

switch (request) {
case VOCTRL_SCREENSHOT_WIN:
*(struct mp_image**)arg = mp_image_new_copy(p->cur_frame);
return VO_TRUE;
case VOCTRL_SET_PANSCAN:
if (vo->config_ok)
reconfig(vo, vo->params);
Expand Down
5 changes: 5 additions & 0 deletions video/out/vo_vaapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,10 @@ static void draw_osd(struct vo *vo)
int rw = mp_rect_w(*rc);
int rh = mp_rect_h(*rc);

// reduce width of last slice to prevent overflow
if (n == num_mod_rc - 1)
rw = w - rc->x0;

void *src = mp_image_pixel_ptr(osd, 0, rc->x0, rc->y0);
void *dst = vaimg.planes[0] + rc->y0 * vaimg.stride[0] + rc->x0 * 4;

Expand Down Expand Up @@ -788,6 +792,7 @@ static int preinit(struct vo *vo)
if (!p->image_formats)
goto fail;

p->mpvaapi->hwctx.hw_imgfmt = IMGFMT_VAAPI;
p->pool = mp_image_pool_new(p);
va_pool_set_allocator(p->pool, p->mpvaapi, VA_RT_FORMAT_YUV420);

Expand Down

0 comments on commit 2839bf1

Please sign in to comment.