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 OverflowWhen 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)
Using ffmpeg in a subprocess
FFMPEG and Pythons subprocess - Stack Overflow
using ffmpeg command line with python's subprocess module
video sequence editor - python subprocess to ffmpeg/ffprobe errors - Blender Stack Exchange
Videos
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?
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.
I've often noticed problems reading standard output (or even standard error!) with subprocess, due to buffering issues that are hard to defeat. My favorite solution, when I do need to read such stdout/stderr from the subprocess, is to switch to using, instead of subprocess, pexpect (or, on Windows, wexpect).
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/