python - 在 Windows 上的 Python Popen 子进程中暂停 FFmpeg 编码

标签 python ffmpeg subprocess signals popen

我正在尝试暂停 FFmpeg 的编码,而它位于 中。非壳子进程(这对于它如何在更大的程序中发挥作用很重要)。这可以通过单独按下键盘上的“暂停/中断”键来完成,我正在尝试将其发送到 Popen。
命令本身必须是跨平台兼容的,所以我不能以任何方式包装它,但我可以根据需要发送信号或运行特定于平台的函数。
我看了how to send a "Ctrl+Break" to a subprocess via pid or handler它建议发送一个信号,但这引发了“ValueError:不支持的信号:21”

from subprocess import Popen, PIPE
import signal


if __name__ == '__main__':
    command = "ffmpeg.exe -y -i example_video.mkv -map 0:v -c:v libx265 -preset slow -crf 18 output.mkv"
    proc = Popen(command, stdin=PIPE, shell=False)

    try:
        proc.send_signal(signal.SIGBREAK)
    finally:
        proc.wait()
然后尝试使用 GenerateConsoleCtrlEvent 来创建 Ctrl+Break 事件,如此处所述 https://docs.microsoft.com/en-us/windows/console/generateconsolectrlevent
from subprocess import Popen, PIPE
import ctypes


if __name__ == '__main__':
    command = "ffmpeg.exe -y -i example_video.mkv -map 0:v -c:v libx265 -preset slow -crf 18 output.mkv"
    proc = Popen(command, stdin=PIPE, shell=False)

    try:
        ctypes.windll.kernel32.GenerateConsoleCtrlEvent(1, proc.pid)
    finally:
        proc.wait()
我试过psutil暂停功能,但即使在“暂停”时,它也会使 CPU 负载保持在很高的水平。
尽管它不适用于整个程序,但我至少尝试过设置 creationflags=CREATE_NEW_PROCESS_GROUP这使得 SIGBREAK 不会出错,但也不会暂停它。因为 Ctrl-Break 事件将完全停止编码而不是暂停它。

最佳答案

Linux/Unix 解决方案:

import subprocess, os, signal
# ...
# Start the task:
proc = subprocess.Popen(..., start_new_session=True)
# ...
def send_signal_to_task(pid, signal):
        #gpid = os.getpgid(pid)  # WARNING This does not work
        gpid = pid  # But this does!
        print(f"Sending {signal} to process group {gpid}...")
        os.killpg(gpid, signal)
# ...
# Pause and resume:
send_signal_to_task(proc.pid, signal.SIGSTOP)
send_signal_to_task(proc.pid, signal.SIGCONT)
通知 start_new_session=TruePopen调用和使用os.killpg而不是 os.killsend_signal_to_task功能。其原因与您报告的即使在暂停状态下也有大量 CPU 使用率的原因相同。 ffmpeg产生许多子进程。 start_new_session=True将创建一个新的进程组和 os.killpg向组中的所有进程发送信号。
跨平台解决方案应该由psutil 提供模块,但您可能应该研究它是否支持进程组作为上述变体:
>>> import psutil
>>> psutil.pids()
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215,
 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932,
 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311,
 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433,
 4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054,
 7055, 7071]
>>> p = psutil.Process(7055)
>>> p.suspend()
>>> p.resume()
引用:https://pypi.org/project/psutil/
关于在 Windows 中模拟进程组的一些提示:Popen waiting for child process even when the immediate child has terminated

关于python - 在 Windows 上的 Python Popen 子进程中暂停 FFmpeg 编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65152998/

相关文章:

python - scrapy:禁用表单请求的过滤是否有意义?

ffmpeg - 连接 N 个命令

php - 我可以从 PHP 调用多核 LAMP 机器上的多个 FFMPEG 进程吗?

nginx - ffmpeg 或 vlc 播放列表到 rtmp 流?

python - 如何对我从 python 数据库中获得的列表求和。错误类型错误 : unsupported operand type(s) for : 'int' and 'tuple'

python - 显示子进程的控制台输出

python - 让 Ipywidgets 与 Jupyter Notebook 中的 Pandas Dataframe 交互

python - 如何绘制时间序列中事件的频率?

python - 子流程变量

python - 获取类型名称作为字符串