I have this ffmpeg command:
ffmpeg -y -i 6.mp4 -vf scale=1280:-2,setsar=1:1 -c:v libx264 -c:a copy 720p.mp4
and I want to implement it via python code. for this I used subprocess function and I use the following code for this:
subprocess.call(['ffmpeg.exe','-y','-i', pname1,'-vf','scale=','1280:-2','setsar=','1:1','-c:v', 'libx264', '-c:a', 'copy', pname2])
pname1 and pname2 are the names of input and output files. this program is running without any error, but it produces nothing. do you know what is the problem?
The correct syntax is:
subprocess.call(['ffmpeg.exe', '-y', '-i', pname1, '-vf', 'scale=1280:-2,setsar=1:1', '-c:v', 'libx264', '-c:a', 'copy', pname2])
Each element in the list (after the first one) represents an argument.
The sperate arguments to FFmpeg may be identified by the spaces between them (when executing FFmpeg in command line).
When executing you original command, I am getting an error message:
[NULL # 0000020fb89bc2c0] Unable to find a suitable output format for '1280:-2'
1280:-2: Invalid argument
The error message is printed to stderr (usually printed to the console).
To see what the process is doing you can capture the output by replacing:
subprocess.call(["command"])
with:
subprocess.check_output(["command"], stderr=subprocess.STDOUT)
See https://docs.python.org/3.9/library/subprocess.html#subprocess.check_output
So your call would become:
ffmpeg_output = subprocess.check_output(
['ffmpeg.exe','-y','-i', pname1,'-vf','scale=','1280:-2','setsar=','1:1','-c:v', 'libx264', '-c:a', 'copy', pname2],
stderr=subprocess.STDOUT
)
print(ffmpeg_output)
Related
I am currently using the following command in python to convert my .webm file to .ogg
subprocess.call(['ffmpeg', '-i', songfile, songfile + ".ogg"])
This prints out a bunch of output which I don't require, But I cannot disable it using this command.
subprocess.call(['ffmpeg', ' -loglevel quiet','-i', songfile, songfile + ".ogg"])
I get error
Unrecognized option '-log-level quiet'.
How can I disable ffmpeg output here?
subprocess.call docs says
To suppress stdout or stderr, supply a value of DEVNULL.
so you might replace
subprocess.call(['ffmpeg', '-i', songfile, songfile + ".ogg"])
using
subprocess.call(['ffmpeg', '-i', songfile, songfile + ".ogg"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Daweo's answer is worth looking at, but here is why your attempt did not work: Remember that there is no shell involved when you do subprocess.call (unless you explicitly ask for it), which means that you need to pass -loglevel quiet as two separate items; ..., '-loglevel', 'quiet', ...
I have this command in ffmpeg that I want to write in Python,
ffmpeg -ss 00:12:14 -i video.mp4 -vframes 1 output.png
Is it possible to write this in Python?
Kinda depends on what you mean by 'write this in Python'.
Using the subprocess module:
import subprocess
cmd = ['ffmpeg', '-ss', '00:12:14', '-i', 'video.mp4', '-vframes', '1', 'output.png']
cmdproc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
while True:
line = cmdproc.stdout.readline()
if not line:
break
(or something similar, since there's check_output(), call()...)
If you mean by a 'native' way of doing that, you can try out ffmpeg-python [1],
though I know nothing about that.
[1] - https://github.com/kkroening/ffmpeg-python
using the python bindings, you'd write it like this:
ffmpeg.input('video.mp4', vframes=1, ss=('00:12:14')).output('output.png').run()
(not 100% sure if the ss filter takes the time params like this, if that doesn't work use count of seconds instead)
I am trying to convert a file or microphone stream to 22050 sample rate and change tempo to double. I can do it using terminal with below code;
#ffmpeg -i test.mp3 -af asetrate=44100*0.5,aresample=44100,atempo=2 output.mp3
But i can not run this terminal code with python subprocess. I try many things but every time fail. Generaly i am taking Requested output format 'asetrate' or 'aresample' or 'atempo' is not suitable output format errors. Invalid argument. How can i run it and take a stream with pipe?
song = subprocess.Popen(["ffmpeg.exe", "-i", sys.argv[1], "-f", "asetrate", "22050", "wav", "pipe:1"],
stdout=subprocess.PIPE)
Your two commands are different. Try:
song = subprocess.Popen(["ffmpeg", "-i", sys.argv[1], "-af", "asetrate=22050,aresample=44100,atempo=2", "-f", "wav", "pipe:1"],
-af is for audio filter.
-f is to manually set muxer/output format
ffmpeg interprets whatever supplied by -af as a single argument that it would then parse internally into separate ones, so splitting them out before passing it via Popen would not achieve the same thing.
The initial example using the terminal should be created using Popen as
subprocess.Popen([
'ffmpeg', '-i', 'test.mp3', '-af', 'asetrate=44100*0.5,aresample=44100,atempo=2',
'output.mp3',
])
So for your actual example with pipe, try instead the following:
song = subprocess.Popen(
["ffmpeg.exe", "-i", sys.argv[1], "-f", "asetrate=22050,wav", "pipe:1"],
stdout=subprocess.PIPE
)
You will then need to call song.communicate() to get the output produced by ffmpeg.exe.
I have found a couple answers that solve the problem of passing wildcards through Popen, but I can't seem to get those solutions to work for my particular case.
I have a project that will merge an audio and video file when a button is pressed, and I need to use subprocess.Popen to execute the command I want:
mergeFile = "ffmpeg -i /home/pi/Video/* -i /home/pi/Audio/test.wav -acodec copy -vcodec copymap 0:v -map 1:a /home/pi/Test/output.mkv"
proc= subprocess.Popen(shlex.split(mergeFiles), shell=True)
I basically want to take whatever file is in my Video folder (my project downloads videos from a camera and the name of the file changes every time a new video is saved) and merge the audio from a separate "Audio" folder and then save that file to yet another folder.
I have tried setting the shell to true, and nothing works.
I also don't know how the glob module would help me in this scenario.
The problem here is the shlex.split(). When used in conjunction with shell=True, it means that only the string ffmpeg is treated as a script, and that the other components of your command line are passed as arguments to that script (which it never looks at / reads).
mergeFile = "ffmpeg -i /home/pi/Video/* -i /home/pi/Audio/test.wav -acodec copy -vcodec copymap 0:v -map 1:a /home/pi/Test/output.mkv"
proc = subprocess.Popen(mergeFile, shell=True)
A better-practice alternative that still uses shell=True (if you're actually parameterizing the directory names and filenames) might be:
mergeFile=[
'ffmpeg -i "$1"/* -i "$2" -acodec copy -vcodec copymap 0:v -map 1:a "$3"',
'_', # placeholder for $0
"/home/pi/Video", # directory for $1 -- can use a variable here
"/home/pi/Audio/test.wav",
"/home/pi/Test/output.mkv",
]
subprocess.Popen(mergeFile, shell=True)
...in which case the script itself is constant (and can't have its meaning changed by values injected via filenames or other parameters), but out-of-band data can be provided.
Even better than that is to stop using shell=True altogether. Consider:
import subprocess, glob
mergeFile=[
'ffmpeg', '-i',
] + (glob.glob('/home/pi/Video/*') or ['/home/pi/Video/*']) + [
'-i', '/home/pi/Audio/test.wav',
'-acodec', 'copy',
'-vcodec', 'copymap', '0:v',
'-map', '1:a1',
'/home/pi/Test/output.mkv'
]
subprocess.Popen(mergefile)
The or ['/home/pi/Video/*'] exists to cause the same error message you'd get with a shell if no files matching the glob exist. Obviously, you could just abort in that case as well.
I want to crop and re encode videos via ffmpeg from within python using subprocesses.
I managed starting a subprocess using a pure string command and shell=True but I want to build more complex commands and would prefer to use shell=False and passing a list of arguments.
So what works is this form (this is a simplified example, there will be multiple streams in the final version):
import subprocess as sp
sp.Popen('ffmpeg.exe -i Test.avi -filter_complex "[0:v]crop=1024:1024:0:0[out1]" -map [out1] out1.mp4', shell=True)
This script produces the expected cropped output video.
For a list of arguments, I tried:
FFMPEG_PATH = 'ffmpeg.exe'
aviP='Test.avi'
sp.Popen([FFMPEG_PATH,
'-i', aviP,
'-filter_complex', '[0:v]crop=1024:1024:0:0[out1]',
'-map', '[out1] out1.mp4'])
When I execute this second version, simply nothing happens. (no error, no output)
I suspect I am messing up something in the map command syntax?
I think I figured it out:
FFMPEG_PATH = 'ffmpeg.exe'
aviP='Test.avi'
sp.Popen([FFMPEG_PATH,
'-i', aviP,
'-filter_complex', '[0:v]crop=1024:1024:0:0[out1]',
'-map', '[out1]', 'out1.mp4'])
is the correct syntax