Simply add ,universal_newlines=True to your subprocess.Popen line.

cmd="ffmpeg -i in.mp4 -y out.avi"
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)
for line in process.stdout:
    print(line)

For now you got line in cycle like:

frame= 1900 fps=453 q=18.6 Lsize=    3473kB time=00:01:16.08 bitrate= 373.9kbits/s

Use the time= value to determine progress in percentage.

Answer from Arseniy Alexandrov on Stack Overflow
🌐
Reddit
reddit.com › r/learnpython › help me understand subprocess (vs os, application is ffmpeg/ffprobe)
r/learnpython on Reddit: Help me understand subprocess (vs OS, application is FFmpeg/FFprobe)
August 13, 2023 -

I forgot to save some of my Jupyter notebook last night, so code that is psudo or actual runs will be marked

Some notes/context:

  • Development environment is Windows/Jupyter running whatever latest/stable Python (3.7?, no idea).

  • FFmpeg/FFprobe is open source video processing and querying software that runs on the host machine

  • This task is to ping FFMpeg on the host machine, and store the output as a variable for Python

I have this running using OS no problem (no pseudo, actually runs):

# importing os module 
import os

# Command to execute
cmd = 'ffmpeg -r 24 -i test1.mkv -r 24 -i test2.mkv -lavfi libvmaf="n_threads=20:n_subsample=10" -f null -'

#Using os.system() method
os.system(cmd)

Psudo output:

[Parsed_libvmaf_0 @ 00000148cfab6a80] VMAF score: 96.393400

Great!

But I need to store this as a variable in Python, which I believe is not possible with the OS.System method

But I just can't seem to figure out how to get subprocess to either work, or return the output (actual code):

# importing sibprocess module
import subprocess

# Command to execute
cmd = 'ffmpeg -r 24 -i test.mkv -r 24 -i testsrtlaopus111.mkv -lavfi libvmaf="n_threads=20:n_subsample=10" -f null -'

# Using os.system() method
returned_value = subprocess.check_output(cmd, shell=True)  

# Runs the cmd, returns output 
print('returned value:', returned_value)

Which runs, I can see the ffmpeg command running in terminal, but once the command in terminal finishes processing, the python returns:

returned value: b''

Instead of the desired output:

[Parsed_libvmaf_0 @ 00000148cfab6a80] VMAF score: 96.393400

What am I doing wrong here?

Discussions

audio - ffmpeg with python subprocess Popen - Stack Overflow
I'm trying to record webcam video from python using ffmpeg. The following ffmpeg works properly when run from the cmd ffmpeg -f dshow -rtbufsize 2000M -i video="HP HD Camera":audio=" More on stackoverflow.com
🌐 stackoverflow.com
python - subprocess call ffmpeg (command line) - Stack Overflow
I have been incorporating subprocess calls in my program. I have had no issues with subprocess calls for other commands, but I am having trouble getting the command line input ffmpeg -r 10 -i fram... More on stackoverflow.com
🌐 stackoverflow.com
Pause a FFmpeg encoding in a Python Popen subprocess on Windows - Stack Overflow
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"... More on stackoverflow.com
🌐 stackoverflow.com
Using ffmpeg in a subprocess
I’m using ffprobe from ffmpeg to get information about user-selected image dimensions. I’m doing this inside of a subprocess, but after my deployed app failed to work I realized I need to detect the right Python executable to use. I found this article helpful for better understanding what ... More on discuss.streamlit.io
🌐 discuss.streamlit.io
0
0
December 22, 2022
🌐
Unixmen
unixmen.com › home › uncategorized › hack ffmpeg with python, part two
Hacking FFmpeg With Python, Part Two
Suppose we want to get all the information stored inside the [FORMAT], [/FORMAT] tags and save it into a python dictionary to make it easier for us to pull out data. The subprocess module is going to help us spawn a process, as shown in the following block of code: import subprocess cmds = ['/usr/local/bin/ffprobe', '-show_format', 'test.mp4'] p = subprocess.Popen(cmds, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
🌐
Medium
artwilton.medium.com › running-ffmpeg-commands-from-a-python-script-676eaf2b2739
Running FFmpeg commands from a Python Script | by Arthur Wilton | Medium
May 4, 2021 - The buildFFmpegCommand() function is responsible to take the returned user input from grabUserInput() and formatting it properly for the subprocess module. To run a shell command with subprocess you must provide it with a list of strings.
Top answer
1 of 1
6

We may add double quotes for letting Python subprocess know the string is one argument, and we have to close FFmpeg gracefully.

Adding double quotes:
Replace the following part video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" with:
"video=""HP HD Camera"":audio=""Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"""
Doubling the quotes "" is required because " is between quotes " ... ".

We may also use it without the "": "video=HP HD Camera:audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)".


For getting a playable file, we have to close FFmpeg gracefully.
For simply recording 10 seconds, we may add -t 10 argument.

For closing FFmpeg gracefully programmatically, we may write 'q'.encode("GBK") to stdin pipe of FFmpeg sub-process.
Writing q simulates that q key is pressed by the user (stop recording).

  • Add stdin=subprocess.PIPE argument to subprocess.Popen.

  • After time.sleep(10) add:

     recorder.stdin.write('q'.encode("GBK"))  # Simulate user pressing q key
     recorder.communicate()
    
  • Add recorder.wait() (instead of recorder.terminate() and recorder.kill()).


As good practice we may also add shlex.split(...) for converting the command line to a list of arguments.
In Windows it supposed to work without it, but in Linux it's not.

Code sample:

import subprocess, time, shlex

recorder = subprocess.Popen(shlex.split('ffmpeg -f dshow -rtbufsize 2000M -t 60 -i """video=HP HD Camera:audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"":""audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"""'
                                        ' -y -vcodec libx264 -crf 24 output.mp4'), stdin=subprocess.PIPE, shell=False)

time.sleep(10)

recorder.stdin.write('q'.encode("GBK"))  # Simulate user pressing q key
recorder.communicate()
recorder.wait()
Find elsewhere
Top answer
1 of 1
2

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

🌐
Streamlit
discuss.streamlit.io › community cloud
Using ffmpeg in a subprocess - Community Cloud - Streamlit
December 22, 2022 - I’m using ffprobe from ffmpeg to get information about user-selected image dimensions. I’m doing this inside of a subprocess, but after my deployed app failed to work I realized I need to detect the right Python executable to use. I found this article helpful for better understanding what ...
🌐
Reddit
reddit.com › r › GNURadio › comments › 13vo77l › how_to_run_ffmpeg_as_a_pipe_subprocess_for
How to run FFMPEG as a PIPE subprocess for GNURadio ...
May 30, 2023 - #!/usr/bin/env python3 import subprocess VISIB_LINES = 588 PIXEL_PER_LINE = 720 VIDEO_SCALE = '{}:{}'.format(PIXEL_PER_LINE, VISIB_LINES) ffmpeg = subprocess.Popen(['/usr/bin/ffmpeg', '-i', '/run/media/fubar/Micro Storage/Titan-overdrive2-720x588-RGB.avi', '-c:v', 'rawvideo', '-vf', 'scale=' + VIDEO_SCALE + ':force_original_aspect_ratio=decrease,pad=' + VIDEO_SCALE + ':(ow-iw)/2:(oh-ih)/2', '-c:v', 'rawvideo', '-f', 'rawvideo', '-pix_fmt', 'yuv444p', '-r', '50', '-loglevel', 'quiet', # '-y', '-'], shell=True, stdout = subprocess.PIPE, stdin=subprocess.PIPE) ffmpeg.stdin.close()
🌐
Readthedocs
madmom.readthedocs.io › en › v0.13.2 › _modules › madmom › audio › ffmpeg.html
madmom.audio.ffmpeg — madmom 0.13.2 documentation
Returns ------- samples : str a binary string of samples """ # check input file type if not isinstance(infile, str): raise ValueError("only file names are supported as `infile`, not %s." % infile) # assemble ffmpeg call call = _assemble_ffmpeg_call(infile, "pipe:1", fmt, sample_rate, num_channels, skip, max_len, cmd) if hasattr(subprocess, 'check_output'): # call ffmpeg (throws exception on error) signal = subprocess.check_output(call) else: # this is an old version of Python, do subprocess.check_output manually proc = subprocess.Popen(call, stdout=subprocess.PIPE, bufsize=-1) signal, _ = proc.communicate() if proc.returncode != 0: raise subprocess.CalledProcessError(proc.returncode, call) return signal ·
🌐
Stack Overflow
stackoverflow.com › questions › 76589263 › innosetup-python-subprocess-popen-ffmpeg
InnoSetup python subprocess Popen ffmpeg - Stack Overflow
self.p1 = Popen([self.ffmpeg_path,'-y','-loglevel','quiet','-i',self.retransmition_url,'epalxeis-radio.mp3'],stdin=PIPE,stdout=PIPE,stderr=PIPE, bufsize=1) which read an web radio stream and saves it locally with filename "epalxeis-radio.mp3" Using python to launch the script - works!
🌐
Ask Ubuntu
askubuntu.com › questions › 64331 › python-ffmpeg-command-line-issues
11.04 - Python/FFMPEG command line issues - Ask Ubuntu
subprocess.Popen(command, shell=True) However we can't test here if this resolves your codec issue. Share · Improve this answer · Follow · answered Oct 5, 2011 at 6:56 · Takkat · 145k5555 gold badges318318 silver badges434434 bronze badges 1 · Nope, this doesn't work. I've already tried. The program exits and ffmpeg spits out it's version number, libraries, and this: 'Hyper fast Audio and Video encoder usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}... Use -h to get full help or, even better, run 'man ffmpeg'' norway-firemen – norway-firemen ·
🌐
Stack Overflow
stackoverflow.com › questions › 77152110 › python-subprocess-popen-or-os-popen
bash - Python Subprocess.Popen or os.popen - Stack Overflow
My aim is to have the Python script run, make the file from FFMPEG input then move on to another step in the script. Bashing my head against the wall here... ... subprocess.Popen expects a list of strings for non-shell calls and a string for shell calls. Try adding shell=True to the subprocess.Popen command.
🌐
GRASS GIS
grass.osgeo.org › grass78 › manuals › libpython › _modules › imaging › images2avi.html
imaging.images2avi — Python library documentation documentation
Requires the "ffmpeg" application: ... (formatter,) command += "-g 1 -vcodec %s %s " % (encoding, outputOptions) command += "output.avi" # Run ffmpeg S = subprocess.Popen(command, shell=True, cwd=tempDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Show what ffmpeg has to ...
🌐
Stack Overflow
devres.zoomquiet.top › data › 20181202005312 › index.html
FFMPEG and Pythons subprocess - Stack Overflow
while 1: print convert.ffmpeg.stdout.readline() print convert.ffmpeg.stderr.readline() Disclaimer: I haven't tested this in Python, but I made a comparable application using Java. ... He is already redirecting stderr to stdout. – Christian Oudard Sep 21 '09 at 17:04 · Gorgapor, are you sure he is? – Matthew Talbert Sep 21 '09 at 17:15 · Yes, the stderr is redirected in the code snippit on the line with subprocess.Popen -- of course it can be cut off if you don't use the scroll bar under the code snippit...
Top answer
1 of 2
2

Instead of adding -nosdtin, avoid using shell=True when opening FFmpeg subprocess.

Python code sample:

import subprocess as sp
import shlex
import psutil
from time import sleep

# Open FFmpeg subprocess with opened stdin pipe (generate synthetic pattern for testing):
process = sp.Popen(shlex.split('ffmpeg -hide_banner -y -re -f lavfi -i testsrc=size=384x216:rate=1 -c:v libx264 -pix_fmt yuv420p test.mp4'), stdin=sp.PIPE)
ps_process = psutil.Process(pid=process.pid)  # Pass the PID of FFmpeg subprocess to PsUtil.

sleep(3)  # Wait 3 seconds for testing ("recored 3 seconds")
ps_process.suspend()  # Suspend FFmpeg process for 3 seconds
sleep(3)  # Wait 3 seconds
ps_process.resume()  # Resume FFmpeg process.
sleep(3)
ps_process.suspend()
sleep(3)
ps_process.resume()

# Close FFmpeg gracefully:
process.stdin.write(b'q')  # Simulate user pressing q key for gracefully closing FFmpeg.
process.communicate()
process.wait()

In Linux, when using: process = sp.Popen(shlex.split('ffmpeg ...'), stdin=sp.PIPE, shell=True), I am getting the following message usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}... and Use -h to get full help or, even better, run 'man ffmpeg'.

2 of 2
2

I'm not sure of the usefulness of the psutils library here, but I do have a script working with standard libraries that'll send SIGSTOP and SIGCONT signals to the process group spawned by the ffmpeg command:

#!/usr/bin/env python3

import subprocess
import time
import os

ffmpeg_cmd = "ffmpeg -i /tmp/in.mp4 -vcodec libx264 /tmp/out.mp4"

process = subprocess.Popen(
        ffmpeg_cmd,
        shell=True,
        preexec_fn=os.setsid,
        stdout= open(os.devnull, 'w'),
        stderr=subprocess.STDOUT)

while True:
    os.killpg(os.getpgid(process.pid), subprocess.signal.SIGSTOP)
    print("asleep")
    time.sleep(10)
    os.killpg(os.getpgid(process.pid), subprocess.signal.SIGCONT)
    print("awake")
    time.sleep(5)

Example output is:

$ ./test.py 
asleep
awake
asleep
awake
asleep
Traceback (most recent call last):
  File "/home/preston/superuser/1856303/./test.py", line 19, in <module>
    time.sleep(10)
KeyboardInterrupt
$ 

You can see the work starting and stopping in a resource monitor: