When you use subprocess, your command must either be a string that looks exactly like what you would type on the command line (and you set shell=True), or a list where each command is an item in the list (and you take the default shell=False). In either case, you have to deal with the variable part of the string. For instance, the operating system has no idea what "%03d" is, you have to fill it in.
I can't tell from your question exactly what the parameters are, but lets assume you want to convert frame 3, it would look something like this in a string:
my_frame = 3
subprocess.call(
'ffmpeg -r 10 -i frame%03d.png -r ntsc movie%03d.mpg' % (my_frame, my_frame),
shell=True)
Its kinda subtle in this example, but that's risky. Suppose these things were in a directory whose name name had spaces (e.g., ./My Movies/Scary Movie). The shell would be confused by those spaces.
So, you can put it into a list and avoid the problem
my_frame = 3
subprocess.call([
'ffmpeg',
'-r', '10',
'-i', 'frame%03d.png' % my_frame,
'-r', 'ntsc',
'movie%03d.mpg' % my_frame,
])
More typing, but safer.
Answer from tdelaney on Stack Overflowpython - subprocess call ffmpeg (command line) - Stack Overflow
Help me understand subprocess (vs OS, application is FFmpeg/FFprobe)
Multiple Ffmpeg stream into a single subprocess pipeline
python - Getting realtime output from ffmpeg to be used in progress bar (PyQt4, stdout) - Stack Overflow
Videos
When you use subprocess, your command must either be a string that looks exactly like what you would type on the command line (and you set shell=True), or a list where each command is an item in the list (and you take the default shell=False). In either case, you have to deal with the variable part of the string. For instance, the operating system has no idea what "%03d" is, you have to fill it in.
I can't tell from your question exactly what the parameters are, but lets assume you want to convert frame 3, it would look something like this in a string:
my_frame = 3
subprocess.call(
'ffmpeg -r 10 -i frame%03d.png -r ntsc movie%03d.mpg' % (my_frame, my_frame),
shell=True)
Its kinda subtle in this example, but that's risky. Suppose these things were in a directory whose name name had spaces (e.g., ./My Movies/Scary Movie). The shell would be confused by those spaces.
So, you can put it into a list and avoid the problem
my_frame = 3
subprocess.call([
'ffmpeg',
'-r', '10',
'-i', 'frame%03d.png' % my_frame,
'-r', 'ntsc',
'movie%03d.mpg' % my_frame,
])
More typing, but safer.
I found this alternative, simple, answer to also work.
subprocess.call('ffmpeg -r 10 -i frame%03d.png -r ntsc '+str(out_movie), shell=True)
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?
In this specific case for capturing ffmpeg's status output (which goes to STDERR), this SO question solved it for me: FFMPEG and Pythons subprocess
The trick is to add universal_newlines=True to the subprocess.Popen() call, because ffmpeg's output is in fact unbuffered but comes with newline-characters.
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)
Also note that in this code sample the STDERR status output is directly redirected to subprocess.STDOUT
The only way I've found to get dynamic feedback/output from a child process is to use something like pexpect:
#! /usr/bin/python
import pexpect
cmd = "foo.sh"
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([pexpect.EOF,
'waited (\d+)'])
while True:
i = thread.expect_list(cpl, timeout=None)
if i == 0: # EOF
print "the sub process exited"
break
elif i == 1:
waited_time = thread.match.group(1)
print "the sub process waited %d seconds" % int(waited_time)
thread.close()
the called sub process foo.sh just waits a random amount of time between 10 and 20 seconds, here's the code for it:
#! /bin/sh
n=5
while [ $n -gt 0 ]; do
ns=`date +%N`
p=`expr $ns % 10 + 10`
sleep $p
echo waited $p
n=`expr $n - 1`
done
You'll want to use some regular expression that matches the output you're getting from ffmpeg and does some kind of calculation on it to show the progress bar, but this will at least get you the unbuffered output from ffmpeg.
I would like to understand how to read the following ffmpeg instruction
Your ffmpeg command is semi-obfuscated by scripting so the actual command is not known, but here's an explanation of each option:
-iindicates the input.-r 1sets output frame rate to 1. This is not needed if you want to output a single image or if you want to output all images. In this example it is used to output one frame per second which would skip many frames.-s qvgasets output width x height to "qvga" which is an alias for 320x240.-t 1sets the output duration to 1 second. This is not needed if you want to output a single image or if you want to output all images. It is often added by rookie users trying to output a single image but-frames:v 1should be used instead.-f image2An often superfluous option used to set the output format or muxer. It is used if your output name is ambiguous (perhaps due to scripting). Otherwise,ffmpegwill automatically choose the proper muxer for image outputs.
how can l adapt it to get all the frames of a given video ?
The simplest, unscripted command to get all of the frames is:
ffmpeg -i input %04d.png
This will output 0001.png, 0002.png, 0003.png, etc. If you want more than a numerical sequence you can use something like output_%05d.png which would result in output_00001.png.
For more info see FFmpeg Documentation: Image Muxer.
import subprocess
L=subprocess.call('ffmpeg -i %s -r 1 -s qvga -t 1 -f image2 %s' % (videoName,frameName), shell=True)
Information:
import subprocess: The subprocess module enables you to start new applications from your Python program.L=subprocess.call(...): Assign the output of thecall()method to variableL.ffmpeg -i %s -r 1 -s qvga -t 1 -f image2 %s' % (videoName,frameName), shell=True: Command to run hereffmpeg-i %s: input file name gotten fromvideoNamevariable -->input file url-r 1: frame rate.-s qvga: frame size.-f image2: Force input or output file format-t 1: When used as an output option (before an output url), stop writing the output after its duration reaches duration.% (videoName,frameName): Python string formatting that will replace%ssequences in the previous string with the items in the tuple.shell=True: Make use of specific shell features like word splitting or parameter expansion
Usage:
#!/usr/bin/env python
import subprocess
L=subprocess.call('ffmpeg -r 5 -i out.ogv fmprg_%04d.png', shell=True)
L()
- Make executable:
chmod u+x filename.sh, - Run with:
./filename.sh
Information:
fmprg_%04d.png: Creates images with 0000, 0001, 0002, 0004, ... between fmprg_ and .png.
Read:
man ffmpeg
https://pythonspot.com/en/tag/subprocess/