From d8a0356b3bf8751938da7696b49da25bce5cd791 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 14 Apr 2015 14:36:15 +0200 Subject: player: silence spam in verbose mode when playing audio with cover art When playing cover art, it conceptually reaches EOF as soon as the image was put on the VO, causing the EOF message to be repeated every time new audio was decoded. Just silence the message. --- player/video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'player') diff --git a/player/video.c b/player/video.c index 6c41593c72..2d3840b6b3 100644 --- a/player/video.c +++ b/player/video.c @@ -784,7 +784,7 @@ void write_video(struct MPContext *mpctx, double endpts) vo_still_displaying(vo) ? STATUS_DRAINING : STATUS_EOF; mpctx->delay = 0; mpctx->last_av_difference = 0; - MP_VERBOSE(mpctx, "video EOF (status=%d)\n", mpctx->video_status); + MP_DBG(mpctx, "video EOF (status=%d)\n", mpctx->video_status); return; } -- cgit v1.2.3 From d55c41501f3500d5d301f3cb4ea5c40816f9baae Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 15 Apr 2015 22:43:02 +0200 Subject: subprocess: move implementation for deatched subprocesses --- player/command.c | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) (limited to 'player') diff --git a/player/command.c b/player/command.c index 88b3164436..6db3b2100b 100644 --- a/player/command.c +++ b/player/command.c @@ -3960,39 +3960,6 @@ static void overlay_uninit(struct MPContext *mpctx) osd_set_external2(mpctx->osd, NULL); } -struct subprocess_args { - struct mp_log *log; - char **args; -}; - -static void *run_subprocess(void *ptr) -{ - struct subprocess_args *p = ptr; - pthread_detach(pthread_self()); - - mp_msg_flush_status_line(p->log); - - char *err = NULL; - if (mp_subprocess(p->args, NULL, NULL, NULL, NULL, &err) < 0) - mp_err(p->log, "Running subprocess failed: %s\n", err); - - talloc_free(p); - return NULL; -} - -static void subprocess_detached(struct mp_log *log, char **args) -{ - struct subprocess_args *p = talloc_zero(NULL, struct subprocess_args); - p->log = mp_log_new(p, log, NULL); - int num_args = 0; - for (int n = 0; args[n]; n++) - MP_TARRAY_APPEND(p, p->args, num_args, talloc_strdup(p, args[n])); - MP_TARRAY_APPEND(p, p->args, num_args, NULL); - pthread_t thread; - if (pthread_create(&thread, NULL, run_subprocess, p)) - talloc_free(p); -} - struct cycle_counter { char **args; int counter; @@ -4599,7 +4566,7 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) char *args[MP_CMD_MAX_ARGS + 1] = {0}; for (int n = 0; n < cmd->nargs; n++) args[n] = cmd->args[n].v.s; - subprocess_detached(mpctx->log, args); + mp_subprocess_detached(mpctx->log, args); break; } -- cgit v1.2.3 From 533b0c70e1f2cf5c1358c7147ae5546fcf1f6a64 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 16 Apr 2015 21:55:10 +0200 Subject: video: do not show decoder framedrops if they're not requested libavcodec makes it impossible to distinguish dropped frames (requested with AVCodecContext.skip_frame), and cases when the decoder simply does not return a frame by default (such as with VP9, which has invisible reference frames). This confuses users when decoding VP9 video. It's basically a cosmetic issue, so just paint it over by ignoring them if framedropping is disabled. --- player/video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'player') diff --git a/player/video.c b/player/video.c index 2d3840b6b3..978790b31c 100644 --- a/player/video.c +++ b/player/video.c @@ -405,7 +405,8 @@ static int decode_image(struct MPContext *mpctx) talloc_free(pkt); if (had_packet && !d_video->waiting_decoded_mpi && - mpctx->video_status == STATUS_PLAYING) + mpctx->video_status == STATUS_PLAYING && + (mpctx->opts->frame_dropping & 2)) { mpctx->dropped_frames_total++; mpctx->dropped_frames++; -- cgit v1.2.3 From 547976633f41c245b9accd6906166bb450e13557 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 16 Apr 2015 22:06:47 +0200 Subject: command: let screenshot_to_file command overwrite files The old behavior does not make too much sense after all. If you don't want to file to be overwritten, the user can check this manually. This is a change in behavior - let's hope nobody actually relied on it. --- player/screenshot.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'player') diff --git a/player/screenshot.c b/player/screenshot.c index ec01adffaa..3a1a41a4ca 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -370,11 +370,6 @@ void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, bool old_osd = ctx->osd; ctx->osd = osd; - if (mp_path_exists(filename)) { - screenshot_msg(ctx, SMSG_ERR, "Screenshot: file '%s' already exists.", - filename); - goto end; - } char *ext = mp_splitext(filename, NULL); if (ext) opts.format = ext; -- cgit v1.2.3 From f4292ebf52fb2e58a1ddbefb06bccd47a38bdc99 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 16 Apr 2015 22:16:04 +0200 Subject: vf_screenshot: remove this filter It's entirely useless, especially now that vo.c handles screenshots in a generic way, and requires no special VO support. There are some potential weird use-cases, but actually I've never seen it being used. --- player/screenshot.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'player') diff --git a/player/screenshot.c b/player/screenshot.c index 3a1a41a4ca..f722b9561f 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -32,7 +32,6 @@ #include "options/path.h" #include "video/mp_image.h" #include "video/decode/dec_video.h" -#include "video/filter/vf.h" #include "video/out/vo.h" #include "video/image_writer.h" #include "sub/osd.h" @@ -330,11 +329,7 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode) if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd)) mode = 0; - // vf_screenshot - if (mpctx->d_video && mpctx->d_video->vfilter) - vf_control_any(mpctx->d_video->vfilter, VFCTRL_SCREENSHOT, &image); - - if (!image && mpctx->video_out && mpctx->video_out->config_ok) { + if (mpctx->video_out && mpctx->video_out->config_ok) { vo_wait_frame(mpctx->video_out); // important for each-frame mode if (mode != MODE_FULL_WINDOW) -- cgit v1.2.3 From c64e4e48d97b9af2b241179ee87765e5d17fff95 Mon Sep 17 00:00:00 2001 From: xylosper Date: Tue, 21 Apr 2015 00:50:43 +0900 Subject: command: disc-mouse-on-button property This property indicates whether mouse cursor is located on button or not for disc naviation. --- player/command.c | 9 +++++++++ player/core.h | 1 + player/discnav.c | 23 +++++++++++++++++++++++ 3 files changed, 33 insertions(+) (limited to 'player') diff --git a/player/command.c b/player/command.c index 6db3b2100b..68ad29f02b 100644 --- a/player/command.c +++ b/player/command.c @@ -702,6 +702,14 @@ static int mp_property_disc_menu(void *ctx, struct m_property *prop, return m_property_flag_ro(action, arg, !!state); } +static int mp_property_mouse_on_button(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + bool on = mp_nav_mouse_on_button(mpctx); + return m_property_flag_ro(action, arg, on); +} + /// Current chapter (RW) static int mp_property_chapter(void *ctx, struct m_property *prop, int action, void *arg) @@ -3262,6 +3270,7 @@ static const struct m_property mp_properties[] = { {"playback-time", mp_property_playback_time}, {"disc-title", mp_property_disc_title}, {"disc-menu-active", mp_property_disc_menu}, + {"disc-mouse-on-button", mp_property_mouse_on_button}, {"chapter", mp_property_chapter}, {"edition", mp_property_edition}, {"disc-titles", mp_property_disc_titles}, diff --git a/player/core.h b/player/core.h index 23547ac630..9ed452ffad 100644 --- a/player/core.h +++ b/player/core.h @@ -373,6 +373,7 @@ void mp_nav_destroy(struct MPContext *mpctx); void mp_nav_user_input(struct MPContext *mpctx, char *command); void mp_handle_nav(struct MPContext *mpctx); int mp_nav_in_menu(struct MPContext *mpctx); +bool mp_nav_mouse_on_button(struct MPContext *mpctx); // loadfile.c void uninit_player(struct MPContext *mpctx, unsigned int mask); diff --git a/player/discnav.c b/player/discnav.c index d66b569d4b..719e88ac8f 100644 --- a/player/discnav.c +++ b/player/discnav.c @@ -42,6 +42,7 @@ struct mp_nav_state { bool nav_eof; bool nav_menu; bool nav_draining; + bool nav_mouse_on_button; // Accessed by OSD (possibly separate thread) // Protected by the given lock @@ -91,6 +92,25 @@ int mp_nav_in_menu(struct MPContext *mpctx) return mpctx->nav_state ? mpctx->nav_state->nav_menu : -1; } +static void update_mouse_on_button(struct MPContext *mpctx) +{ + mp_notify_property(mpctx, "disc-mouse-on-button"); +} + +static void set_mouse_on_button(struct MPContext *mpctx, bool in) +{ + struct mp_nav_state *nav = mpctx->nav_state; + if (nav->nav_mouse_on_button != in) { + nav->nav_mouse_on_button = in; + update_mouse_on_button(mpctx); + } +} + +bool mp_nav_mouse_on_button(struct MPContext *mpctx) +{ + return mpctx->nav_state ? mpctx->nav_state->nav_mouse_on_button : false; +} + // If a demuxer is accessing the stream, we have to use demux_stream_control() // to avoid synchronization issues; otherwise access it directly. static int run_stream_control(struct MPContext *mpctx, int cmd, void *arg) @@ -129,6 +149,7 @@ void mp_nav_init(struct MPContext *mpctx) MP_INPUT_ALLOW_VO_DRAGGING | MP_INPUT_ALLOW_HIDE_CURSOR); update_state(mpctx); + update_mouse_on_button(mpctx); } void mp_nav_reset(struct MPContext *mpctx) @@ -159,6 +180,7 @@ void mp_nav_destroy(struct MPContext *mpctx) talloc_free(mpctx->nav_state); mpctx->nav_state = NULL; update_state(mpctx); + update_mouse_on_button(mpctx); } void mp_nav_user_input(struct MPContext *mpctx, char *command) @@ -182,6 +204,7 @@ void mp_nav_user_input(struct MPContext *mpctx, char *command) inp.u.mouse_pos.x = x; inp.u.mouse_pos.y = y; run_stream_control(mpctx, STREAM_CTRL_NAV_CMD, &inp); + set_mouse_on_button(mpctx, inp.mouse_on_button); } else { struct mp_nav_cmd inp = {MP_NAV_CMD_MENU}; inp.u.menu.action = command; -- cgit v1.2.3 From c6d046414b1d31046c39da6399130b39fe54813d Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 20:52:16 +0200 Subject: player: change video-bitrate and audio-bitrate properties Remove the old implementation for these properties. It was never very good, often returned very innaccurate values or just 0, and was static even if the source was variable bitrate. Replace it with the implementation of "packet-video-bitrate". Mark the "packet-..." properties as deprecated. (The effective difference is different formatting, and returning the raw value in bits instead of kilobits.) Also extend the documentation a little. It appears at least some decoders (sipr?) need the AVCodecContext.bit_rate field set, so this one is still passed through. --- player/command.c | 75 +++++++++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 47 deletions(-) (limited to 'player') diff --git a/player/command.c b/player/command.c index 68ad29f02b..f5621ceb01 100644 --- a/player/command.c +++ b/player/command.c @@ -216,14 +216,6 @@ static void mark_seek(struct MPContext *mpctx) cmd->last_seek_time = now; } -static char *format_bitrate(int rate) -{ - if (rate < 1024 * 1024) - return talloc_asprintf(NULL, "%.3f kbps", rate / 1000.0); - - return talloc_asprintf(NULL, "%.3f mbps", rate / 1000000.0); -} - static char *format_file_size(int64_t size) { double s = size; @@ -1644,20 +1636,6 @@ static int mp_property_audio_codec(void *ctx, struct m_property *prop, return m_property_strdup_ro(action, arg, c); } -/// Audio bitrate (RO) -static int mp_property_audio_bitrate(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - if (!mpctx->d_audio) - return M_PROPERTY_UNAVAILABLE; - if (action == M_PROPERTY_PRINT) { - *(char **)arg = format_bitrate(mpctx->d_audio->bitrate); - return M_PROPERTY_OK; - } - return m_property_int_ro(action, arg, mpctx->d_audio->bitrate); -} - /// Samplerate (RO) static int mp_property_samplerate(void *ctx, struct m_property *prop, int action, void *arg) @@ -2337,21 +2315,6 @@ static int mp_property_video_codec(void *ctx, struct m_property *prop, return m_property_strdup_ro(action, arg, c); } - -/// Video bitrate (RO) -static int mp_property_video_bitrate(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - if (!mpctx->d_video) - return M_PROPERTY_UNAVAILABLE; - if (action == M_PROPERTY_PRINT) { - *(char **)arg = format_bitrate(mpctx->d_video->bitrate); - return M_PROPERTY_OK; - } - return m_property_int_ro(action, arg, mpctx->d_video->bitrate); -} - static int property_imgparams(struct mp_image_params p, int action, void *arg) { if (!p.imgfmt) @@ -3030,7 +2993,8 @@ static int mp_property_packet_bitrate(void *ctx, struct m_property *prop, int action, void *arg) { MPContext *mpctx = ctx; - int type = (intptr_t)prop->priv; + int type = (uintptr_t)prop->priv & ~0x100; + bool old = (uintptr_t)prop->priv & 0x100; if (!mpctx->demuxer) return M_PROPERTY_UNAVAILABLE; @@ -3039,8 +3003,23 @@ static int mp_property_packet_bitrate(void *ctx, struct m_property *prop, if (demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_BITRATE_STATS, &r) < 1) return M_PROPERTY_UNAVAILABLE; - // r[type] is in bytes/second -> kilobits - return m_property_int64_ro(action, arg, r[type] * 8 / 1000.0 + 0.5); + // r[type] is in bytes/second -> bits + double rate = r[type] * 8; + + // Same story, but used kilobits for some reason. + if (old) + return m_property_int64_ro(action, arg, rate / 1000.0 + 0.5); + + if (action == M_PROPERTY_PRINT) { + rate /= 1000; + if (rate < 1000) { + *(char **)arg = talloc_asprintf(NULL, "%d kbps", (int)rate); + } else { + *(char **)arg = talloc_asprintf(NULL, "%.3f mbps", rate / 1000.0); + } + return M_PROPERTY_OK; + } + return m_property_int64_ro(action, arg, rate); } static int mp_property_cwd(void *ctx, struct m_property *prop, @@ -3317,7 +3296,6 @@ static const struct m_property mp_properties[] = { {"audio-delay", mp_property_audio_delay}, {"audio-format", mp_property_audio_format}, {"audio-codec", mp_property_audio_codec}, - {"audio-bitrate", mp_property_audio_bitrate}, {"audio-samplerate", mp_property_samplerate}, {"audio-channels", mp_property_channels}, {"aid", mp_property_audio}, @@ -3352,7 +3330,6 @@ static const struct m_property mp_properties[] = { {"video-params", mp_property_vd_imgparams}, {"video-format", mp_property_video_format}, {"video-codec", mp_property_video_codec}, - {"video-bitrate", mp_property_video_bitrate}, M_PROPERTY_ALIAS("dwidth", "video-out-params/dw"), M_PROPERTY_ALIAS("dheight", "video-out-params/dh"), M_PROPERTY_ALIAS("width", "video-params/w"), @@ -3399,11 +3376,15 @@ static const struct m_property mp_properties[] = { {"ab-loop-a", mp_property_ab_loop}, {"ab-loop-b", mp_property_ab_loop}, -#define PROPERTY_BITRATE(name, type) \ - {name, mp_property_packet_bitrate, (void *)(intptr_t)type} - PROPERTY_BITRATE("packet-video-bitrate", STREAM_VIDEO), - PROPERTY_BITRATE("packet-audio-bitrate", STREAM_AUDIO), - PROPERTY_BITRATE("packet-sub-bitrate", STREAM_SUB), +#define PROPERTY_BITRATE(name, old, type) \ + {name, mp_property_packet_bitrate, (void *)(uintptr_t)((type)|(old?0x100:0))} + PROPERTY_BITRATE("packet-video-bitrate", true, STREAM_VIDEO), + PROPERTY_BITRATE("packet-audio-bitrate", true, STREAM_AUDIO), + PROPERTY_BITRATE("packet-sub-bitrate", true, STREAM_SUB), + + PROPERTY_BITRATE("video-bitrate", false, STREAM_VIDEO), + PROPERTY_BITRATE("audio-bitrate", false, STREAM_AUDIO), + PROPERTY_BITRATE("sub-bitrate", false, STREAM_SUB), #define PROPERTY_TV_COLOR(name, type) \ {name, mp_property_tv_color, (void *)(intptr_t)type} -- cgit v1.2.3 From f13266014f328fed9eda41047f0a1700348ba923 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 23:00:12 +0200 Subject: client API: add glue for making full use of mpv_command_node() Until now, the return value was always MPV_FORMAT_NONE. Now a command can actually set it. This will be used in one of the following commits. --- player/client.c | 15 +++++++++------ player/command.c | 4 ++-- player/command.h | 3 ++- player/playloop.c | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) (limited to 'player') diff --git a/player/client.c b/player/client.c index 614d64205f..43c7c07c60 100644 --- a/player/client.c +++ b/player/client.c @@ -954,6 +954,7 @@ static int run_async(mpv_handle *ctx, void (*fn)(void *fn_data), void *fn_data) struct cmd_request { struct MPContext *mpctx; struct mp_cmd *cmd; + struct mpv_node *res; int status; struct mpv_handle *reply_ctx; uint64_t userdata; @@ -962,7 +963,7 @@ struct cmd_request { static void cmd_fn(void *data) { struct cmd_request *req = data; - int r = run_command(req->mpctx, req->cmd); + int r = run_command(req->mpctx, req->cmd, req->res); req->status = r >= 0 ? 0 : MPV_ERROR_COMMAND; talloc_free(req->cmd); if (req->reply_ctx) { @@ -971,7 +972,7 @@ static void cmd_fn(void *data) } } -static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd) +static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd, mpv_node *res) { if (!ctx->mpctx->initialized) return MPV_ERROR_UNINITIALIZED; @@ -986,6 +987,7 @@ static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd) struct cmd_request req = { .mpctx = ctx->mpctx, .cmd = cmd, + .res = res, }; run_locked(ctx, cmd_fn, &req); return req.status; @@ -993,21 +995,22 @@ static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd) int mpv_command(mpv_handle *ctx, const char **args) { - return run_client_command(ctx, mp_input_parse_cmd_strv(ctx->log, args)); + return run_client_command(ctx, mp_input_parse_cmd_strv(ctx->log, args), NULL); } int mpv_command_node(mpv_handle *ctx, mpv_node *args, mpv_node *result) { - int r = run_client_command(ctx, mp_input_parse_cmd_node(ctx->log, args)); + struct mpv_node rn = {.format = MPV_FORMAT_NONE}; + int r = run_client_command(ctx, mp_input_parse_cmd_node(ctx->log, args), &rn); if (result && r >= 0) - *result = (mpv_node){.format = MPV_FORMAT_NONE}; + *result = rn; return r; } int mpv_command_string(mpv_handle *ctx, const char *args) { return run_client_command(ctx, - mp_input_parse_cmd(ctx->mpctx->input, bstr0((char*)args), ctx->name)); + mp_input_parse_cmd(ctx->mpctx->input, bstr0((char*)args), ctx->name), NULL); } static int run_cmd_async(mpv_handle *ctx, uint64_t ud, struct mp_cmd *cmd) diff --git a/player/command.c b/player/command.c index f5621ceb01..376f2b6bed 100644 --- a/player/command.c +++ b/player/command.c @@ -4040,7 +4040,7 @@ static bool check_property_autorepeat(char *property, struct MPContext *mpctx) return true; } -int run_command(MPContext *mpctx, mp_cmd_t *cmd) +int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *res) { struct command_ctx *cmdctx = mpctx->command_ctx; struct MPOpts *opts = mpctx->opts; @@ -4692,7 +4692,7 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) case MP_CMD_COMMAND_LIST: { for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next) - run_command(mpctx, sub); + run_command(mpctx, sub, NULL); break; } diff --git a/player/command.h b/player/command.h index 1a36c79570..447e01c011 100644 --- a/player/command.h +++ b/player/command.h @@ -21,11 +21,12 @@ struct MPContext; struct mp_cmd; struct mp_log; +struct mpv_node; void command_init(struct MPContext *mpctx); void command_uninit(struct MPContext *mpctx); -int run_command(struct MPContext *mpctx, struct mp_cmd *cmd); +int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *res); char *mp_property_expand_string(struct MPContext *mpctx, const char *str); char *mp_property_expand_escaped_string(struct MPContext *mpctx, const char *str); void property_print_help(struct mp_log *log); diff --git a/player/playloop.c b/player/playloop.c index 1f480cf3ba..1c10c3e962 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -67,7 +67,7 @@ void mp_process_input(struct MPContext *mpctx) mp_cmd_t *cmd = mp_input_read_cmd(mpctx->input); if (!cmd) break; - run_command(mpctx, cmd); + run_command(mpctx, cmd, NULL); mp_cmd_free(cmd); mp_dispatch_queue_process(mpctx->dispatch, 0); } -- cgit v1.2.3 From ccfe4d64184ae4c2983ae6b099c7c7ebb3770d0f Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 23:05:52 +0200 Subject: client API: add MPV_FORMAT_BYTE_ARRAY type This will be used in the following commit, which adds screenshot_raw. The reasoning is that this will be better for binding scripting languages. One could special-case the screenshot_raw commit and define fixed semantics for passing through a pointer using the current API, like formatting a pointer as string. But that would be ridiculous and unclean. --- player/lua.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'player') diff --git a/player/lua.c b/player/lua.c index 43f549b4ed..51c0e1a752 100644 --- a/player/lua.c +++ b/player/lua.c @@ -860,6 +860,9 @@ static void pushnode(lua_State *L, mpv_node *node) lua_rawset(L, -3); } break; + case MPV_FORMAT_BYTE_ARRAY: + lua_pushlstring(L, node->u.ba->data, node->u.ba->size); + break; default: // unknown value - what do we do? // for now, set a unique dummy value -- cgit v1.2.3 From a3680d1b2d137461008d38486cdb2d5013291e61 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 23:11:03 +0200 Subject: client API: add a screenshot_raw command Requested. The wild code for setting up the mpv_node probably deserves to be cleaned up later. Fixes #1800. --- player/command.c | 39 +++++++++++++++++++++++++++++++++++++++ player/screenshot.c | 10 ++++++++++ player/screenshot.h | 3 +++ 3 files changed, 52 insertions(+) (limited to 'player') diff --git a/player/command.c b/player/command.c index 376f2b6bed..d210398946 100644 --- a/player/command.c +++ b/player/command.c @@ -4040,6 +4040,22 @@ static bool check_property_autorepeat(char *property, struct MPContext *mpctx) return true; } +static struct mpv_node *add_map_entry(struct mpv_node *dst, const char *key) +{ + struct mpv_node_list *list = dst->u.list; + assert(dst->format == MPV_FORMAT_NODE_MAP && dst->u.list); + MP_TARRAY_GROW(list, list->values, list->num); + MP_TARRAY_GROW(list, list->keys, list->num); + list->keys[list->num] = talloc_strdup(list, key); + return &list->values[list->num++]; +} + +#define ADD_MAP_INT(dst, name, i) (*add_map_entry(dst, name) = \ + (struct mpv_node){ .format = MPV_FORMAT_INT64, .u.int64 = (i) }); + +#define ADD_MAP_CSTR(dst, name, s) (*add_map_entry(dst, name) = \ + (struct mpv_node){ .format = MPV_FORMAT_STRING, .u.string = (s) }); + int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *res) { struct command_ctx *cmdctx = mpctx->command_ctx; @@ -4552,6 +4568,29 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re screenshot_to_file(mpctx, cmd->args[0].v.s, cmd->args[1].v.i, msg_osd); break; + case MP_CMD_SCREENSHOT_RAW: { + if (!res) + return -1; + struct mp_image *img = screenshot_get_rgb(mpctx, cmd->args[0].v.i); + if (!img) + return -1; + struct mpv_node_list *info = talloc_zero(NULL, struct mpv_node_list); + talloc_steal(info, img); + *res = (mpv_node){ .format = MPV_FORMAT_NODE_MAP, .u.list = info }; + ADD_MAP_INT(res, "w", img->w); + ADD_MAP_INT(res, "h", img->h); + ADD_MAP_INT(res, "stride", img->stride[0]); + ADD_MAP_CSTR(res, "format", "bgr0"); + struct mpv_byte_array *ba = talloc_ptrtype(info, ba); + *ba = (struct mpv_byte_array){ + .data = img->planes[0], + .size = img->stride[0] * img->h, + }; + *add_map_entry(res, "data") = + (struct mpv_node){.format = MPV_FORMAT_BYTE_ARRAY, .u.ba = ba,}; + break; + } + case MP_CMD_RUN: { char *args[MP_CMD_MAX_ARGS + 1] = {0}; for (int n = 0; n < cmd->nargs; n++) diff --git a/player/screenshot.c b/player/screenshot.c index f722b9561f..a47de292d5 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -357,6 +357,16 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode) return image; } +struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode) +{ + struct mp_image *mpi = screenshot_get(mpctx, mode); + if (!mpi) + return NULL; + struct mp_image *res = convert_image(mpi, IMGFMT_BGR0, mpctx->log); + talloc_free(mpi); + return res; +} + void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, bool osd) { diff --git a/player/screenshot.h b/player/screenshot.h index 84b7ef4f58..9ebe9ef76e 100644 --- a/player/screenshot.h +++ b/player/screenshot.h @@ -39,6 +39,9 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame, void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, bool osd); +// mode is the same as in screenshot_request() +struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode); + // Called by the playback core code when a new frame is displayed. void screenshot_flip(struct MPContext *mpctx); -- cgit v1.2.3 From 74ae74db0c7c21535664d881007aa238bb8c8408 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 23:19:19 +0200 Subject: video: cleanup some old log messages These are basically MPlayer leftovers, and barely useful due to being redundant with other messages. The FPS message is used somewhere else. --- player/video.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'player') diff --git a/player/video.c b/player/video.c index 978790b31c..eb8967ce89 100644 --- a/player/video.c +++ b/player/video.c @@ -296,6 +296,8 @@ int reinit_video_chain(struct MPContext *mpctx) d_video->fps = sh->video->fps; d_video->vo = mpctx->video_out; + MP_VERBOSE(d_video, "Container reported FPS: %f\n", sh->video->fps); + if (opts->force_fps) { d_video->fps = opts->force_fps; MP_INFO(mpctx, "FPS forced to %5.3f.\n", d_video->fps); -- cgit v1.2.3 From 4ae8fc326d544f83777ad4f038ad6587af507fab Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Apr 2015 23:21:38 +0200 Subject: player: cleanup update_fps() function It was called only in 2 places, one of them redundant (the container FPS can not change). --- player/core.h | 1 - player/video.c | 17 +++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) (limited to 'player') diff --git a/player/core.h b/player/core.h index 9ed452ffad..714fd5d4bd 100644 --- a/player/core.h +++ b/player/core.h @@ -491,7 +491,6 @@ int reinit_video_chain(struct MPContext *mpctx); int reinit_video_filters(struct MPContext *mpctx); void write_video(struct MPContext *mpctx, double endpts); void mp_force_video_refresh(struct MPContext *mpctx); -void update_fps(struct MPContext *mpctx); void uninit_video_out(struct MPContext *mpctx); void uninit_video_chain(struct MPContext *mpctx); diff --git a/player/video.c b/player/video.c index eb8967ce89..78df2b2f0a 100644 --- a/player/video.c +++ b/player/video.c @@ -76,15 +76,6 @@ static const char av_desync_help_text[] = " with --no-video, --no-audio, or --no-sub.\n" "If none of this helps you, file a bug report.\n\n"; -void update_fps(struct MPContext *mpctx) -{ -#if HAVE_ENCODING - struct dec_video *d_video = mpctx->d_video; - if (mpctx->encode_lavc_ctx && d_video) - encode_lavc_set_video_fps(mpctx->encode_lavc_ctx, d_video->fps); -#endif -} - static void set_allowed_vo_formats(struct vf_chain *c, struct vo *vo) { vo_query_formats(vo, c->allowed_output_formats); @@ -303,7 +294,11 @@ int reinit_video_chain(struct MPContext *mpctx) MP_INFO(mpctx, "FPS forced to %5.3f.\n", d_video->fps); MP_INFO(mpctx, "Use --no-correct-pts to force FPS based timing.\n"); } - update_fps(mpctx); + +#if HAVE_ENCODING + if (mpctx->encode_lavc_ctx && d_video) + encode_lavc_set_video_fps(mpctx->encode_lavc_ctx, d_video->fps); +#endif vo_control(mpctx->video_out, VOCTRL_GET_HWDEC_INFO, &d_video->hwdec_info); @@ -771,8 +766,6 @@ void write_video(struct MPContext *mpctx, double endpts) if (mpctx->paused && mpctx->video_status >= STATUS_READY) return; - update_fps(mpctx); - int r = video_output_image(mpctx, endpts); MP_TRACE(mpctx, "video_output_image: %d\n", r); -- cgit v1.2.3 From dbeb1053962e2eb35d380e6b6a5bc7a3c3d60d76 Mon Sep 17 00:00:00 2001 From: xylosper Date: Tue, 21 Apr 2015 06:47:13 +0900 Subject: command: demuxer-cache-time property Approximate time of video buffered in the demuxer, in seconds. Same as `demuxer-cache-duration` but returns the last timestamp of bufferred data in demuxer. Signed-off-by: wm4 --- player/command.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'player') diff --git a/player/command.c b/player/command.c index d210398946..3556986473 100644 --- a/player/command.c +++ b/player/command.c @@ -1383,6 +1383,24 @@ static int mp_property_demuxer_cache_duration(void *ctx, struct m_property *prop return m_property_double_ro(action, arg, s.ts_duration); } +static int mp_property_demuxer_cache_time(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + if (!mpctx->demuxer) + return M_PROPERTY_UNAVAILABLE; + + struct demux_ctrl_reader_state s; + if (demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_READER_STATE, &s) < 1) + return M_PROPERTY_UNAVAILABLE; + + double ts = s.ts_range[1]; + if (ts == MP_NOPTS_VALUE) + return M_PROPERTY_UNAVAILABLE; + + return m_property_double_ro(action, arg, ts); +} + static int mp_property_demuxer_cache_idle(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3271,6 +3289,7 @@ static const struct m_property mp_properties[] = { {"cache-size", mp_property_cache_size}, {"cache-idle", mp_property_cache_idle}, {"demuxer-cache-duration", mp_property_demuxer_cache_duration}, + {"demuxer-cache-time", mp_property_demuxer_cache_time}, {"demuxer-cache-idle", mp_property_demuxer_cache_idle}, {"cache-buffering-state", mp_property_cache_buffering}, {"paused-for-cache", mp_property_paused_for_cache}, @@ -3463,7 +3482,8 @@ static const char *const *const mp_event_property_change[] = { E(MPV_EVENT_METADATA_UPDATE, "metadata", "filtered-metadata", "media-title"), E(MPV_EVENT_CHAPTER_CHANGE, "chapter", "chapter-metadata"), E(MP_EVENT_CACHE_UPDATE, "cache", "cache-free", "cache-used", "cache-idle", - "demuxer-cache-duration", "demuxer-cache-idle", "paused-for-cache"), + "demuxer-cache-duration", "demuxer-cache-idle", "paused-for-cache", + "demuxer-cache-time"), E(MP_EVENT_WIN_RESIZE, "window-scale"), E(MP_EVENT_WIN_STATE, "window-minimized", "display-names", "display-fps"), E(MP_EVENT_AUDIO_DEVICES, "audio-device-list"), -- cgit v1.2.3 From 0b240bca8aa27a861d6c56be6808662f0e49d26b Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 21 Apr 2015 21:53:24 +0200 Subject: player: do not load encoding config files in non-encoding mode It's annoying and unnecessary. They can be manually loaded if really needed (for things like previewing). Also remove the #if. It was for suppressing warnings, and we don't need to be so careful about this in the relatively obscure encoding mode. --- player/configfiles.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'player') diff --git a/player/configfiles.c b/player/configfiles.c index e056b43e8e..b7d3795f60 100644 --- a/player/configfiles.c +++ b/player/configfiles.c @@ -72,16 +72,14 @@ void mp_parse_cfgfiles(struct MPContext *mpctx) // So we "divert" normal options into a separate section, and the diverted // section is never used - unless maybe it's explicitly referenced from an // encoding profile. - if (encoding) + if (encoding) { section = "playback-default"; - // The #if is a stupid hack to avoid errors if libavfilter is not available. -#if HAVE_LIBAVFILTER && HAVE_ENCODING - char *cf = mp_find_config_file(NULL, mpctx->global, "encoding-profiles.conf"); - if (cf) - m_config_parse_config_file(mpctx->mconfig, cf, SECT_ENCODE, 0); - talloc_free(cf); -#endif + char *cf = mp_find_config_file(NULL, mpctx->global, "encoding-profiles.conf"); + if (cf) + m_config_parse_config_file(mpctx->mconfig, cf, SECT_ENCODE, 0); + talloc_free(cf); + } load_all_cfgfiles(mpctx, section, "mpv.conf|config"); -- cgit v1.2.3 From 589533d97ad0bf861a555b7402410297541bf96c Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 22 Apr 2015 18:52:55 +0200 Subject: osc: paint over a crash Sometimes tries to index a nil object when seeking close to the end of the file. See #1101. --- player/lua/osc.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'player') diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 26e2f89c5f..082dae599f 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -266,11 +266,13 @@ end -- get the currently selected track of , OSC-style counted function get_track(type) local track = mp.get_property(type) - if (track == "no" or track == nil) then - return 0 - else - return tracks_mpv[type][tonumber(track)].osc_id + if track ~= "no" and track ~= nil then + local tr = tracks_mpv[type][tonumber(track)] + if tr then + return tr.osc_id + end end + return 0 end -- cgit v1.2.3 From daabbe364007fc7546df63981422b53b9a20c6fc Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 22 Apr 2015 20:55:05 +0200 Subject: lua: add utils.format_json() function Requested. Why not. --- player/lua.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'player') diff --git a/player/lua.c b/player/lua.c index 51c0e1a752..4ef772fd84 100644 --- a/player/lua.c +++ b/player/lua.c @@ -1255,6 +1255,23 @@ static int script_parse_json(lua_State *L) return 3; } +static int script_format_json(lua_State *L) +{ + void *tmp = mp_lua_PITA(L); + struct mpv_node node; + makenode(tmp, &node, L, 1); + char *dst = talloc_strdup(tmp, ""); + if (json_write(&dst, &node) >= 0) { + lua_pushstring(L, dst); + lua_pushnil(L); + } else { + lua_pushnil(L); + lua_pushstring(L, "error"); + } + talloc_free_children(tmp); + return 2; +} + #define FN_ENTRY(name) {#name, script_ ## name} struct fn_entry { const char *name; @@ -1303,6 +1320,7 @@ static const struct fn_entry utils_fns[] = { FN_ENTRY(join_path), FN_ENTRY(subprocess), FN_ENTRY(parse_json), + FN_ENTRY(format_json), {0} }; -- cgit v1.2.3 From e9ca0b1522a799e9d52e6aafc58fc316398f40b6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 23 Apr 2015 19:21:17 +0200 Subject: demux_mkv: move global options to the demuxer The options don't change, but they're now declared and used privately by demux_mkv.c. This also brings with it a minor refactor of the subpreroll seek handling - merge the code from playloop.c into demux_mkv.c. The change in demux.c is pretty much equivalent as well. --- player/playloop.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'player') diff --git a/player/playloop.c b/player/playloop.c index 1c10c3e962..c34ae7e6da 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -240,8 +240,6 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek, } if (hr_seek) demuxer_style |= SEEK_HR; - if (hr_seek || opts->mkv_subtitle_preroll) - demuxer_style |= SEEK_SUBPREROLL; if (hr_seek) demuxer_amount -= hr_seek_offset; -- cgit v1.2.3 From df1f22214baadd2cc15b4cd24ebd400b6095b5c0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 23 Apr 2015 22:08:07 +0200 Subject: osc: add nil check for element.eventresponder Possibly fixes a crash (see #1101). --- player/lua/osc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'player') diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 082dae599f..7f602b8689 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -448,7 +448,7 @@ function render_elements(master_ass) style_ass:append(string.format("{\\1a&H%X&\\2a&H%X&\\3a&H%X&\\4a&H%X&}", ar[1], ar[2], ar[3], ar[4])) - if (state.active_element == n) then + if element.eventresponder and (state.active_element == n) then -- run render event functions if not (element.eventresponder.render == nil) then -- cgit v1.2.3 From 8d31ad85ec0ec49cc7f7f72c330f3570e57ceffe Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 24 Apr 2015 22:15:31 +0200 Subject: player: don't show A/V desync message in non-sense situations last_av_difference can be MP_NOPTS_VALUE under certain circumstances (like no video timestamp yet). This triggered the desync message, because fabs(MP_NOPTS_VALUE) is quite a large value. We don't want to show a message in this situation. --- player/video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'player') diff --git a/player/video.c b/player/video.c index 78df2b2f0a..e96f7dad82 100644 --- a/player/video.c +++ b/player/video.c @@ -724,9 +724,9 @@ static void update_avsync_after_frame(struct MPContext *mpctx) mpctx->last_av_difference = a_pos - mpctx->video_pts + opts->audio_delay; 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) + if (a_pos == MP_NOPTS_VALUE || mpctx->video_pts == MP_NOPTS_VALUE) { mpctx->last_av_difference = MP_NOPTS_VALUE; - if (fabs(mpctx->last_av_difference) > 0.5 && !mpctx->drop_message_shown) { + } else if (fabs(mpctx->last_av_difference) > 0.5 && !mpctx->drop_message_shown) { MP_WARN(mpctx, "%s", av_desync_help_text); mpctx->drop_message_shown = true; } -- cgit v1.2.3 From e11abdbad2fff17968c914212d5fd68d7536ddeb Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 24 Apr 2015 22:34:55 +0200 Subject: player: flush decoder even if cover art is decoded Fixes PNG cover art not showing up immediately (for example when running with --pause). libavformat exports embedded cover art as a single packet. For example, a PNG attachment simply contains the PNG image, which can be sent to the decoder. Normally you would expect that the PNG decoder would return 1 frame for 1 packet, without any delays. But this stopped working, and it incurs a 1 frame delay. This is perfectly legal (even if unexpected), so let our code feed the decoder packets until we get something back. (In theory feeding the packet instead of a real flush packet is still somewhat questionable.) --- player/video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'player') diff --git a/player/video.c b/player/video.c index e96f7dad82..d35a9de011 100644 --- a/player/video.c +++ b/player/video.c @@ -377,7 +377,7 @@ static int decode_image(struct MPContext *mpctx) if (d_video->header->attached_picture) { d_video->waiting_decoded_mpi = video_decode(d_video, d_video->header->attached_picture, 0); - return VD_EOF; + return d_video->waiting_decoded_mpi ? VD_EOF : VD_PROGRESS; } struct demux_packet *pkt; -- cgit v1.2.3