Considering that pyFFmpeg is just a wrapper over the libraries, I'd say you shouldn't have any negligible performance difference between the 2, since they use the same libraries at the core.
Answer from John Doe on Stack Overflowwhich is the best programing language with a library to write ffmpeg readable commands?
ffmpeg in python script - Stack Overflow
I have trouble converted ffmpeg command to ffmpeg-python - Stack Overflow
How do I integrate the FFMPEG commands with Python Script? - Stack Overflow
Videos
I'm starting with fmpeg, currently I use it with python, I write the commands as if using the cli, and I create a subprocess to get the result.
But I'm already at a point where I write very long commands and it becomes difficult to read, maintain and reuse.
What is the best programming language with some library that allows me to write them in a way that is easier to read and maintain?
The idea would be to use that language only to write the ffmpeg scripts, either via api, stdout, and continue with python to read the result since I use a lot more things there than ffmpeg.
Thanks
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
» pip install ffmpeg-python
I would recommend PyAV. it's a proper wrapper around ffmpeg's libraries.
the other mentioned packages use the "subprocess" approach, which is limited and inefficient. these libraries may be more convenient than plain ffmpeg APIs.
You could execute that command from Python via subprocess module, of course, but it would better to use library like https://github.com/kkroening/ffmpeg-python
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'))
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")