I am trying to build a script that converts video files via ffmpeg inside Python 3.
Via Windows PowerShell I successfully obtained the desired result via the following command:
ffmpeg -i test.webm -c:v libx264 converted.mp4
However, if I try to repeat the same operation inside python via the following code:
import subprocess
from os import getcwd
print(getcwd()) # current directory
subprocess.call(["ffmpeg", " -f test.webm -c libx264 converted.mp4"])
I get the following error:
Output #0, mp4, to ' -f test.webm -c libx264 converted.mp4':
Output file #0 does not contain any stream
I am in the correct folder where the files are. Do you have better methods to execute commands in shell via Python? That should preferably work on different platforms.
try this:
import shlex
cmd = shlex.split("ffmpeg -f test.webm -c libx264 converted.mp4")
subprocess.call(cmd)
you need pass each argument as a single element in a list, that's how argv works, or let shell do the split:
subprocess.call("ffmpeg -f test.webm -c libx264 converted.mp4", shell=True)
Related
I have a bunch of audio and video files and their corresponding start time in a stream.
Like this diagram below:
How can I combine this all into a single video file efficiently?
I've tried ffmpeg but it was too slow (I don't know if I used ffmpeg correctly or not)
This is my ffmpeg command example:
ffmpeg -i audio_0_3.mp3 -i audio_1_4.mp3 -i audio_2_5.mp3 -i audio_2_6.mp3 -i audio_2_7.mp3 -i audio_3_10.mp3 -i audio_3_8.mp3 -i audio_3_9.mp3 \
-filter_complex [0:a]adelay=0ms[s0];[1:a]adelay=36282ms[s1];[2:a]adelay=462385ms[s2];[3:a]adelay=686909ms[s3];[4:a]adelay=876931ms[s4];[5:a]adelay=1675187ms[s5];[6:a]adelay=1339944ms[s6];[7:a]adelay=1567946ms[s7];[s0][s1][s2][s3][s4][s5][s6][s7]amix=inputs=8[s8] \
-map [s8] out.mp4
I am trying to run an ffmpeg command that records my screen and creates an .mp4 file of the recording in python. The command works when I run it in my shell, but is not working when I am running it in a Python script using subprocess.
The issue is that when running it with subprocess, the output.mp4 file is not created.
Here is the command:
timeout 10 ffmpeg -video_size 1920x1080 -framerate 60 -f x11grab -i :0.0+0,0 -f alsa -ac 2 -i pulse -acodec aac -strict experimental output.mp4
Here is the python code:
os.chdir('/home/user/Desktop/myProject/')
subprocess.run('timeout 5 ffmpeg -video_size 1920x1080 -framerate 60 -f x11grab -i :0.0+0,0 -f alsa -ac 2 -i pulse -acodec aac -strict experimental out.mp4')
Is there an additional configuration to add so that subprocess can write output files?
subprocess.run returns an CompletedProcess object. You should assign that to a variable, and then print out all output and errors of the command (Because i think, ffmpeg gives an error and doesn't try to write the file at all, but you do not see that).
Additionally, you have to either set the keyword argument shell to True, or use shlex.split, else the command will not be formatted right. shlex.split is the preferred way, as you can read here:
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).
And you do not want to manually convert the string into a list of arguments !
And there is no need to stop ffmpeg from the outside (another reason why your file might not get written). Use the builtin command line option -t for that.
import shlex
import subprocess
import os
os.chdir('/home/user/Desktop/myProject/')
p = subprocess.run(shlex.split("ffmpeg -video_size 1920x1080 -framerate 60 -f x11grab -i :0.0+0,0 -f alsa -ac 2 -i pulse -acodec aac -strict experimental -t 00:00:05 out.mp4"), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
print(p.stdout)
Instead of using timeout you may use the -t option as posted here.
Add -t 00:00:05 argument, and remove the timeout:
subprocess.run('ffmpeg -video_size 1920x1080 -framerate 60 -f x11grab -i :0.0+0,0 -f alsa -ac 2 -i pulse -acodec aac -strict experimental -t 00:00:05 out.mp4')
I think it's more elegant to use command argument than using timeout for terminating the process.
On Windows, for hysterical reasons, you can pass in a single string without shell=True and it will work. For portable code, you need to either specify shell=True, or refactor the code to avoid it (which is generally recommended wherever feasible).
Note also that subprocess.run() has keyword arguments both for setting a timeout and for specifying the working directory for the subprocess.
subprocess.run(
['ffmpeg', '-video_size', '1920x1080', '-framerate', '60',
'-f', 'x11grab', '-i', ':0.0+0,0', '-f', 'alsa',
'-ac', '2', '-i', 'pulse', '-acodec', 'aac',
'-strict', 'experimental', 'out.mp4'],
cwd='/home/user/Desktop/myProject/', # current working directory
timeout=5, # timeout
check=True # check for errors
)
With check=True you will get an exception if the command fails, the timeout will raise an exception if the command times out, regardless of whether you have check=True.
Without more information about what failed, it's hard to specify how exactly to fix your problem; but with this, hopefully you should at least get enough information in error messages to guide you.
i have a tmp directory which contains a collection of image frames and audio files. i am using linux mint 19.3 and python3.8. in the terminal I type
ffmpeg -i tmp/%d.png -vcodec png tmp/output.mov -y
and ffmpeg -i tmp/output.mov -i tmp/audio.mp3 -codec copy output.mov -y
then the collection of images and audio in the directory will become a complete video. that I asked
when I run it in python using the syntax
call(["ffmpeg", "-i", "tmp/%d.png" , "-vcodec", "png", "tmp/output.mov", "-y"],stdout=open(os.devnull, "w"), stderr=STDOUT)
and
call(["ffmpeg", "-i", "tmp/output.mov", "-i", "tmp/audio.mp3", "-codec", "copy", "output.mov", "-y"],stdout=open(os.devnull, "w"), stderr=STDOUT)
it does not merge into a video (without output error)
I tried the syntax
os.system("ffmpeg -i tmp/%d.png -vcodec png tmp/output.mov -y")
and
os.system("ffmpeg -i tmp/output.mov -i tmp/audio.mp3 -codec copy output.mov -y"), the video failed to merge with the error output tmp/output.mov: No such file or directory
Please help. thank you
Use the full path
Instead of tmp/output.mov use /tmp/output.mov. Do this for the rest of the inputs and outputs.
Do everything in one command
ffmpeg -y -i /tmp/%d.png -i /tmp/audio.mp3 -codec copy -shortest output.mov
I am trying to run shell code from a python file to submit another python file to a computing cluster. The shell code is as follows:
#BSUB -J Proc[1]
#BSUB -e ~/logs/proc.%I.%J.err
#BSUB -o ~/logs/proc.%I.%J.out
#BSUB -R "span[hosts=1]"
#BSUB -n 1
python main.py
But when I run it from python like the following I can't get it to work:
from os import system
system('bsub -n 1 < #BSUB -J Proc[1];#BSUB -e ~/logs/proc.%I.%J.err;#BSUB -o ~/logs/proc.%I.%J.out;#BSUB -R "span[hosts=1]";#BSUB -n 1;python main.py')
Is there something I'm doing wrong here?
If I understand correctly, all the #BSUB stuff is text that should be fed to the bsub command as input; bsub is run locally, then runs those commands for you on the compute node.
In that case, you can't just do:
bsub -n 1 < #BSUB -J Proc[1];#BSUB -e ~/logs/proc.%I.%J.err;#BSUB -o ~/logs/proc.%I.%J.out;#BSUB -R "span[hosts=1]";#BSUB -n 1;python main.py
That's interpreted by the shell as "run bsub -n 1 and read from a file named OH CRAP A COMMENT STARTED AND NOW WE DON'T HAVE A FILE TO READ!"
You could fix this with MOAR HACKERY (using echo or here strings taking further unnecessary dependencies on shell execution). But if you want to feed stdin input, the best solution is to use a more powerful tool for the task, the subprocess module:
# Open a process (no shell wrapper) that we can feed stdin to
proc = subprocess.Popen(['bsub', '-n', '1'], stdin=subprocess.PIPE)
# Feed the command series you needed to stdin, then wait for process to complete
# Per Michael Closson, can't use semi-colons, bsub requires newlines
proc.communicate(b'''#BSUB -J Proc[1]
#BSUB -e ~/logs/proc.%I.%J.err
#BSUB -o ~/logs/proc.%I.%J.out
#BSUB -R "span[hosts=1]"
#BSUB -n 1
python main.py
''')
# Assuming the exit code is meaningful, check it here
if proc.returncode != 0:
# Handle a failed process launch here
This avoids a shell launch entirely (removing the issue with needing to deal with comment characters at all, along with all the other issues with handling shell metacharacters), and is significantly more explicit about what is being run locally (bsub -n 1) and what is commands being run in the bsub session (the stdin).
The #BSUB directives are parsed by the bsub binary, which doesn't support ; as a delimiter. You need to use newlines. This worked for me.
#!/usr/bin/python
import subprocess;
# Open a process (no shell wrapper) that we can feed stdin to
proc = subprocess.Popen(['bsub', '-n', '1'], stdin=subprocess.PIPE)
# Feed the command series you needed to stdin, then wait for process to complete
input="""#!/bin/sh
#BSUB -J mysleep
sleep 101
"""
proc.communicate(input);
*** So obviously I got the python code from #ShadowRanger. +1 his answer. I would have posted this as a comment to his answer if SO supported python code in a comment.
I need to run two ffmpeg commands, one after the other i.e., wait until the first command has finished, and then run the second command. The first command is
ffmpeg -threads 8 -i D:\imagesequence\dpx\brn_055.%04d.dpx D:\imagesequence\dpx\test2.mov
and the second is
ffmpeg -i D:/imagesequence/background.jpg -vf "movie='D\:/imagesequence/dpx/thumbnail.jpg' [watermark]; [in][watermark] overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/3 [out]" D:/imagesequence/dpx/final_with_text_mod_04.jpg
What is the best way to accomplish this in Python?
You don't have to do anything more than calling 2 times a ffmpeg command with subprocess python module, this is already the default behaviour
import subprocess
execstr1 = 'ffmpeg -x -y -z ...'
execstr2 = 'ffmpeg -a -b -c ...'
out1 = subprocess.check_output(execstr1, shell=True)
out2 = subprocess.check_output(execstr2, shell=True)