I am trying to pause an encode of FFmpeg while it is in a non-shell subprocess (This is important to how it plays into a larger program). This can be done by presssing the "Pause / Break" key on the keyboard by itself, and I am trying to send that to Popen.
The command itself must be cross platform compatible, so I cannot wrap it in any way, but I can send signals or run functions that are platform specific as needed.
I looked at how to send a "Ctrl+Break" to a subprocess via pid or handler and it suggested to send a signal, but that raised a "ValueError: Unsupported signal: 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()
Then attempted to use GenerateConsoleCtrlEvent to create a Ctrl+Break event as described here https://learn.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()
I have tried psutil
pause feature, but it keeps the CPU load really high even when "paused".
Even though it wouldn't work with the program overall, I have at least tried setting creationflags=CREATE_NEW_PROCESS_GROUP
which makes the SIGBREAK not error, but also not pause it. For the Ctrl-Break event will entirely stop the encode instead of pausing it.
A simple method is to suspend it with ctrl+z. Or you could get the PID with pgrep ffmpeg then use kill -s SIGSTOP to suspend.
How to stop ffmpeg remotely? You create an empty file that you write 'q' to when you are ready to stop it.
Click F12 ("Pause") and when ready, resume by giving the console window focus and clicking the "Enter" key. This will not let you close the console window or reboot the computer. Sorry, something went wrong. In Windows 10, run ffmpeg from a PowerShell window. Now while transcoding, if you select a block of text the process will be paused.
This behaviour is actually expected. If you kill ffmpeg process it will exit with code 255 (easily reproducible in the terminal). I don't think introducing a method to kill the process is a good idea though.
If you kill ffmpeg process it will exit with code 255 (easily reproducible in the terminal). I don't think introducing a method to kill the process is a good idea though.
Popen has an encoding parameter that can be used instead of text=True or universal_newlines=True. Python supports two locale-dependent encodings in Windows. “mbcs” (alias “ansi”) is the process ANSI codepage, and “oem” is the process OEM codepage.
Linux/Unix solution:
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)
Notice start_new_session=True
in Popen
call and using of os.killpg
instead of os.kill
in send_signal_to_task
function. The reason for this is the same as as reason for why you have large CPU usage even in paused state as you reported. ffmpeg
spawns a number of child processes. start_new_session=True
will create a new process group and os.killpg
sends signal to all processes in group.
Cross-platform solution is supposed to be provided by psutil
module but you probably should research whether it supports process groups as the variant above:
>>> 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()
Reference: https://pypi.org/project/psutil/
Some pointers on emulating process groups in Windows: Popen waiting for child process even when the immediate child has terminated
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With