| @@ -5633,6 +5633,91 @@ static void cmd_run(void *p) · 5632 unmodified lines |
| 5633 | talloc_free(args); | 5633 | talloc_free(args); |
| 5634 | } | 5634 | } |
| 5635 | | 5635 | |
| | 5636 | struct subprocess_cb_ctx { |
| | 5637 | struct mp_log *log; |
| | 5638 | void* talloc_ctx; |
| | 5639 | int64_t max_size; |
| | 5640 | bool capture[3]; |
| | 5641 | bstr output[3]; |
| | 5642 | }; |
| | 5643 | |
| | 5644 | static void subprocess_output(struct subprocess_cb_ctx *ctx, int fd, |
| | 5645 | char *data, size_t size) |
| | 5646 | { |
| | 5647 | if (ctx->capture[fd]) { |
| | 5648 | if (ctx->output[fd].len < ctx->max_size) |
| | 5649 | bstr_xappend(ctx->talloc_ctx, &ctx->output[fd], (bstr){data, size}); |
| | 5650 | } else { |
| | 5651 | int msgl = fd == 2 ? MSGL_ERR : MSGL_INFO; |
| | 5652 | mp_msg(ctx->log, msgl, "%.*s", (int)size, data); |
| | 5653 | } |
| | 5654 | } |
| | 5655 | |
| | 5656 | static void subprocess_stdout(void *p, char *data, size_t size) |
| | 5657 | { |
| | 5658 | struct subprocess_cb_ctx *ctx = p; |
| | 5659 | subprocess_output(ctx, 1, data, size); |
| | 5660 | } |
| | 5661 | |
| | 5662 | static void subprocess_stderr(void *p, char *data, size_t size) |
| | 5663 | { |
| | 5664 | struct subprocess_cb_ctx *ctx = p; |
| | 5665 | subprocess_output(ctx, 2, data, size); |
| | 5666 | } |
| | 5667 | |
| | 5668 | static void cmd_subprocess(void *p) |
| | 5669 | { |
| | 5670 | struct mp_cmd_ctx *cmd = p; |
| | 5671 | struct MPContext *mpctx = cmd->mpctx; |
| | 5672 | char **args = cmd->args[0].v.str_list; |
| | 5673 | bool playback_only = cmd->args[1].v.i; |
| | 5674 | |
| | 5675 | if (!args || !args[0]) { |
| | 5676 | MP_ERR(mpctx, "program name missing\n"); |
| | 5677 | cmd->success = false; |
| | 5678 | return; |
| | 5679 | } |
| | 5680 | |
| | 5681 | void *tmp = talloc_new(NULL); |
| | 5682 | struct subprocess_cb_ctx ctx = { |
| | 5683 | .log = mpctx->log, |
| | 5684 | .talloc_ctx = tmp, |
| | 5685 | .max_size = cmd->args[2].v.i, |
| | 5686 | .capture = {0, cmd->args[3].v.i, cmd->args[4].v.i}, |
| | 5687 | }; |
| | 5688 | |
| | 5689 | struct mp_cancel *cancel = NULL; |
| | 5690 | if (playback_only) |
| | 5691 | cancel = mpctx->playback_abort; |
| | 5692 | |
| | 5693 | mp_core_unlock(mpctx); |
| | 5694 | |
| | 5695 | char *error = NULL; |
| | 5696 | int status = mp_subprocess(args, cancel, &ctx, subprocess_stdout, |
| | 5697 | subprocess_stderr, &error); |
| | 5698 | |
| | 5699 | mp_core_lock(mpctx); |
| | 5700 | |
| | 5701 | struct mpv_node *res = &cmd->result; |
| | 5702 | node_init(res, MPV_FORMAT_NODE_MAP, NULL); |
| | 5703 | node_map_add_int64(res, "status", status); |
| | 5704 | node_map_add_flag(res, "killed_by_us", status == MP_SUBPROCESS_EKILLED_BY_US); |
| | 5705 | node_map_add_string(res, "error_string", error ? error : ""); |
| | 5706 | const char *sname[] = {NULL, "stdout", "stderr"}; |
| | 5707 | for (int n = 1; n < 3; n++) { |
| | 5708 | if (!ctx.capture[n]) |
| | 5709 | continue; |
| | 5710 | struct mpv_byte_array *ba = |
| | 5711 | node_map_add(res, sname[n], MPV_FORMAT_BYTE_ARRAY)->u.ba; |
| | 5712 | *ba = (struct mpv_byte_array){ |
| | 5713 | .data = talloc_steal(ba, ctx.output[n].start), |
| | 5714 | .size = ctx.output[n].len, |
| | 5715 | }; |
| | 5716 | } |
| | 5717 | |
| | 5718 | talloc_free(tmp); |
| | 5719 | } |
| | 5720 | |
| 5636 | static void cmd_enable_input_section(void *p) | 5721 | static void cmd_enable_input_section(void *p) |
| 5637 | { | 5722 | { |
| 5638 | struct mp_cmd_ctx *cmd = p; | 5723 | struct mp_cmd_ctx *cmd = p; |
| @@ -6047,6 +6132,17 @@ const struct mp_cmd_def mp_cmds[] = { · 408 unmodified lines |
| 6047 | }}, | 6132 | }}, |
| 6048 | { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } }, | 6133 | { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } }, |
| 6049 | { "run", cmd_run, { ARG_STRING, ARG_STRING }, .vararg = true }, | 6134 | { "run", cmd_run, { ARG_STRING, ARG_STRING }, .vararg = true }, |
| | 6135 | { "subprocess", cmd_subprocess, |
| | 6136 | { |
| | 6137 | OPT_STRINGLIST("args", v.str_list, 0), |
| | 6138 | OPT_FLAG("playback_only", v.i, 0, OPTDEF_INT(1)), |
| | 6139 | OPT_BYTE_SIZE("capture_size", v.i64, 0, 0, INT_MAX, |
| | 6140 | OPTDEF_INT64(64 * 1024 * 1024)), |
| | 6141 | OPT_FLAG("capture_stdout", v.i, 0, OPTDEF_INT(0)), |
| | 6142 | OPT_FLAG("capture_stderr", v.i, 0, OPTDEF_INT(0)), |
| | 6143 | }, |
| | 6144 | .spawn_thread = true, |
| | 6145 | }, |
| 6050 | | 6146 | |
| 6051 | { "set", cmd_set, { ARG_STRING, ARG_STRING } }, | 6147 | { "set", cmd_set, { ARG_STRING, ARG_STRING } }, |
| 6052 | { "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } }, | 6148 | { "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } }, |