| @@ -5633,6 +5633,91 @@ static void cmd_run(void *p) · 5632 unmodified lines |
| 5633 | 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 | 5721 | static void cmd_enable_input_section(void *p) |
| 5637 | 5722 | { |
| 5638 | 5723 | struct mp_cmd_ctx *cmd = p; |
| @@ -6047,6 +6132,17 @@ const struct mp_cmd_def mp_cmds[] = { · 408 unmodified lines |
| 6047 | 6132 | }}, |
| 6048 | 6133 | { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } }, |
| 6049 | 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 | 6147 | { "set", cmd_set, { ARG_STRING, ARG_STRING } }, |
| 6052 | 6148 | { "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } }, |