In Windows one line with spaces should work, but in Linux we have to pass the arguments as list.
We can build the command as a list:
command = ['ffmpeg', '-i', 'head1.png', '-i', 'hdmiSpitting.mov', '-filter_complex', '[0:v][1:v]overlay=0:0', '-pix_fmt', 'yuv420p', '-c:a', 'copy', 'output3.mov']We may also use
shlex.split:import shlex command = shlex.split('ffmpeg -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov')
Adding -y argument:
If the output file output3.mov already exists, FFmpeg prints a message:
File 'output3.mov' already exists. Overwrite? [y/N]
And waits for the user to press y.
In some development environments we can't see the message.
Add -y for overwriting the output if already exists (without asking):
command = shlex.split('ffmpeg -y -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov')
Path issues:
There are cases when ffmpeg executable is not in the execution path.
Using full path may be necessary.
Example for Windows (assuming ffmpeg.exe is in c:\FFmpeg\bin):
command = shlex.split('c:\\FFmpeg\\bin\\ffmpeg.exe -y -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov')
In Linux, the default path is /usr/bin/ffmpeg.
Using shell=True is not recommended and considered "unsafe".
For details see Security Considerations.
The default is False, so we may use subprocess.call(command).
Note: subprocess.run supposes to replace subprocess.call.
See this post for details.
Creating log file by adding -report argument:
In some development environments we can't see FFmpeg messages, which are printed to the console (written to stderr).
Adding -report argument creates a log file with name like ffmpeg-20220624-114156.log.
The log file may tell us what went wrong when we can't see the console.
Example:
import subprocess
import shlex
subprocess.run(shlex.split('ffmpeg -y -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov -report'))
Answer from Rotem on Stack OverflowIn Windows one line with spaces should work, but in Linux we have to pass the arguments as list.
We can build the command as a list:
command = ['ffmpeg', '-i', 'head1.png', '-i', 'hdmiSpitting.mov', '-filter_complex', '[0:v][1:v]overlay=0:0', '-pix_fmt', 'yuv420p', '-c:a', 'copy', 'output3.mov']We may also use
shlex.split:import shlex command = shlex.split('ffmpeg -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov')
Adding -y argument:
If the output file output3.mov already exists, FFmpeg prints a message:
File 'output3.mov' already exists. Overwrite? [y/N]
And waits for the user to press y.
In some development environments we can't see the message.
Add -y for overwriting the output if already exists (without asking):
command = shlex.split('ffmpeg -y -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov')
Path issues:
There are cases when ffmpeg executable is not in the execution path.
Using full path may be necessary.
Example for Windows (assuming ffmpeg.exe is in c:\FFmpeg\bin):
command = shlex.split('c:\\FFmpeg\\bin\\ffmpeg.exe -y -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov')
In Linux, the default path is /usr/bin/ffmpeg.
Using shell=True is not recommended and considered "unsafe".
For details see Security Considerations.
The default is False, so we may use subprocess.call(command).
Note: subprocess.run supposes to replace subprocess.call.
See this post for details.
Creating log file by adding -report argument:
In some development environments we can't see FFmpeg messages, which are printed to the console (written to stderr).
Adding -report argument creates a log file with name like ffmpeg-20220624-114156.log.
The log file may tell us what went wrong when we can't see the console.
Example:
import subprocess
import shlex
subprocess.run(shlex.split('ffmpeg -y -i head1.png -i hdmiSpitting.mov -filter_complex "[0:v][1:v] overlay=0:0" -pix_fmt yuv420p -c:a copy output3.mov -report'))
I ended up using os.system() instead of subprocess and got the results I wanted before returning to see answers on this question. The answer from Rotem is incredibly useful and does solve my issue as well, with the added information of -y parameter.
I'll paste my entire code here, as it may be useful to someone in the future.
import os
os.chdir('/Users/Todd/Desktop/ffmpeg')
background = "01Background/Untitled_Artwork7.png"
backgear = "02Backgear/Surfboard-01.png"
head = "03Head/Goldhead_Goldshell1.png"
eye = "04eye/Keye-01.png"
outfit = "05Outfit/Summershirt-01.png"
headgear = "06Headgear/PopejoyHair_Goldshell1.png"
mouth = "hdmiSpitting.mov"
frontgear = "08Frontgear/TreePot-01.png"
# takes a list of 3 or more files and creates ffmpeg command to overlay them in order
# the first element in the list will be the lowest Z element (farthest back)
def generateCommand(files = []):
command = "ffmpeg"
i = 0
count = 0
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"]
for file in files:
command += " -i " + file
count += 1
command += " -filter_complex \"[0][1]overlay[a];["
while i < count-3:
command += alphabet[i] + "][" + str(i+2) + "]overlay[" + alphabet[i+1] + "];["
i += 1
command += alphabet[i] + "][" + str(i+2) + "]overlay\""
command += " -pix_fmt yuv420p -c:a copy output3.mov"
return command
# Takes two files and overlays file1 over file2
# This is a separate function because of the different command syntax for less than 3 files
def overlayTwoLayers(file1, file2):
command = "ffmpeg -i " + file1 + " -i " + file2 + " -filter_complex \"[0:v][1:v] overlay=0:0\" -pix_fmt yuv420p -c:a copy output3.mov"
os.system(command)
# Call this function with a list of files you want to be compiled
def generateImage(files):
command = generateCommand(files)
os.system(command)
files = []
files.append(background)
files.append(backgear)
files.append(head)
files.append(eye)
files.append(outfit)
files.append(headgear)
files.append(mouth)
files.append(frontgear)
generateImage(files)
print("done")
ffmpeg in python script - Stack Overflow
Running cmd in python - Stack Overflow
How to Run FFmpeg in a Python Step Without Local Installation and No Access to Apt-Get or Pip? - Help - Pipedream
Is there any python implementation of FFmpeg?
Videos
» pip install ffmpeg-python
From a brief look at FFMPY, you could do this using ffmpy.FFmpeg, as that allows any and all FFMPEG command line options, including -f. -- Click the link for documentation.
You could do the FFMPEG command with os.system. You'll need to import OS anyway to iterate through the files.
You would need to iterate through all the files in a directory though. This would be the more challenging bit, it's quite easy with a for loop though.
for filename in os.listdir(path):
if (filename.endswith(".mp4")): #or .avi, .mpeg, whatever.
os.system("ffmpeg -i {0} -f image2 -vf fps=fps=1 output%d.png".format(filename))
else:
continue
The above code iterates through the directory at path, and uses command prompt to execute your given FFMPEG command, using the filename (if it's a video file) in place of mymovie.avi
Dont have reputation to comment, hence adding another response.
Another version of ocelot's answer with the more readable f-string syntax of python -
for filename in os.listdir(path):
if (filename.endswith(".mp4")): #or .avi, .mpeg, whatever.
os.system(f'ffmpeg -i {filename} -f image2 -vf fps=fps=1 output%d.png')
else:
continue
For the later generations looking for the answer, this worked. (You have to separate the command by the spaces.)
import os
import subprocess
os.chdir('C://Users/Alex/')
subprocess.call(['ffmpeg', '-i', 'picture%d0.png', 'output.avi'])
subprocess.call(['ffmpeg', '-i', 'output.avi', '-t', '5', 'out.gif'])
It is better to call subprocess.call in another way.
The preferred way is:
subprocess.call(['ffmpeg', '-i', 'test%d0.png', 'output.avi'])
Alternatively:
subprocess.call('ffmpeg -i test%d0.png output.avi', shell=True)
You can find the reasons for this in the manual. I quote:
args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names). If passing a single string, either shell must be True (see below) or else the string must simply name the program to be executed without specifying any arguments.