Subprocess.call ffmpeg making empty file - python

I am trying to convert video from one format to other.
extension = '.avi'
extension_less_url = '../uploads/video'
import subprocess
subprocess.call(['ffmpeg', '-i', extension_less_url + extension, extension_less_url + '.mp4'])
But above produces an empty file named 'video.mp4'.
How to correct?
This is the error I am getting:
The encoder 'aac' is experimental but experimental codecs are not enabled, add '-strict -2' if you want to use it.

This problem is for '.mp4'. try something else like '.mkv' for the target format of your video.
I've done this and the problem is solved

import subprocess
subprocess.call('ffmpeg -f vfwcap -t 10 -r 25 -i 0 c:/test/sample11.avi')
python have a subprocess module which helps for running exec command.
In case if you want to run multiple cmd or shell commands one after another you can use the following :
subprocess.check_call("cd /home/pi/images; ls", shell=True)
here : "cd /home/pi/images" is one command which is separated using ";" to run another command "ls"

Related

Automated Concatenate with FFMPEG Using Re-Encode

I would like to concaternate a fairly large list of videos using FFMPEG.
The following answer from another question is highly relevant:
https://stackoverflow.com/a/11175851/5065462.
I explain below why it isn't sufficient for me.
I'm using MP4 files.
I am using Windows 10. I'd like to write a bat file with arguments. I'll then call this from either Command Prompt or PowerShell.
I want to automate Option 1 https://stackoverflow.com/a/11175851/5065462 to take as input a txt (or similar) file containing the filepaths for the videos to be concatenated.
I'm happy with all the default [#:v] [#:a] options.
An alternative option is just to write a small program, either in Command Prompt or python3 is fine, which outputs a text string that I just copy+paste into cmd/PS.
Unfortunately, I'm not sure how to use python to get filenames.
Option 2 in https://stackoverflow.com/a/11175851/5065462 looks great. Unfortunatley, the stream-encoding has issues with my mp4 files. I found they are fixed by using Option 1 in the linked answer. However, I don't want to type every filename each time.
The following python script will generate the command described in option 1.
To run, use python3 script_file.py video_directory output.mkv.
video_directory should contain only video files.
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("dir", help="the directory to the videos")
parser.add_argument("output", help="the name of the output file")
args = parser.parse_args()
files = os.listdir(args.dir)
cmd = "ffmpeg "
for file in files:
cmd += f"-i {file} "
cmd += '-filter_complex "'
for i in range(len(files)):
cmd += f"[{i}:v] [{i}:a] "
cmd += f'concat=n={len(files)}:v=1:a=1 [v] [a]" '
cmd += f'-map "[v]" -map "[a]" {args.output}'
print(cmd)
NB: replacing the final line by os.system(cmd) will run the command directly from python.

Quotes without backslash in subprocess command line in python

I'm trying to use ffmpeg from python. The command I need to execute is:
ffmpeg -i test_file-1kB.mp4 -i test_file.mp4 -filter_complex psnr="stats_file=test_file.mp4-1kB.psnr" -f null -
However, my output that is getting passed to subprocess looks like it is escaping the double quotes with backslashes like so:
In[1]: print(subprocess.list2cmdline(psnr_args))
ffmpeg -i test_file-1kB.mp4 -i test_file.mp4 -filter_complex psnr=\"stats_file=test_file.mp4-1kB.psnr\" -f null -
To use subprocess, I build my command line arguments one at a time into a list and then pass the list to subprocess.
psnr_args = []
psnr_args.append("ffmpeg")
#add first input, the encoded video
psnr_args.append("-i")
psnr_args.append(full_output_file_name)
#add second input, the original video
psnr_args.append("-i")
psnr_args.append(video_file)
#Setup the psnr log file
psnr_args.append("-filter_complex")
psnr_args.append('psnr="stats_file=%s.psnr"' % vstats_abs_filename )
#Output the video to null
psnr_args.append("-f")
psnr_args.append("null")
psnr_args.append("-")
print(subprocess.list2cmdline(psnr_args))
run_info_psnr = subprocess.run(psnr_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
After more fiddling, I found a solution that works in this case but may not work in all cases. If I use double quotes as the outer quotes and the single quotes as the inner quotes, the output to subprocess uses a single quote at the same location with no backslash. This is acceptable for ffmpeg. However, for others where double quotes are the only solution, it won't be a fix.
psnr_args.append("psnr='stats_file=%s.psnr'" % vstats_abs_filename )
Output to subprocess looks like this:
In[1]: print(subprocess.list2cmdline(psnr_args))
ffmpeg -i test_file-1kB.mp4 -i test_file.mp4 -filter_complex psnr='stats_file=test_file.mp4-1kB.psnr' -f null -
In shell, the argument:
psnr="stats_file=test_file.mp4-1kB.psnr"
Is absolutely identical to:
psnr=stats_file=test_file.mp4-1kB.psnr
The quotes are removed during the shell's own processing. They are not part of the command passed to ffmpeg, which doesn't expect or understand them. Because you're directly telling the Python subprocess module to invoke a literal argument vector, there's no shell involved, so shell syntax shouldn't be present.
This has something to do with ffmpeg AV filter chain syntax too. You need to run the command like xxxx -filter_complex "psnr='stats.txt'" xxxx. To get this, you should ensure the double quote that encapsulate the filter chain reaches inside. subproces expects a flat list as the first argument, where the command is the first entry. So ['ffmpeg', '-i', "t1.mp4", "-filter_compelx", '"psnr=\'stats.txt\'"', .... and so on ].

Ffmpeg map and filter_complex subprocess - Python

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

Converting a file from .sam to .bam using python subprocess

I would like to start out by saying any help is greatly appreciated. I'm new to Python and scripting in general. I am trying to use a program called samtools view to convert a file from .sam to a .bam I need to be able do what this BASH command is doing in Python:
samtools view -bS aln.sam > aln.bam
I understand that BASH commands like | > < are done using the subprocess stdin, stdout and stderr in Python. I have tried a few different methods and still can't get my BASH script converted correctly. I have tried:
cmd = subprocess.call(["samtools view","-bS"], stdin=open(aln.sam,'r'), stdout=open(aln.bam,'w'), shell=True)
and
from subprocess import Popen
with open(SAMPLE+ "."+ TARGET+ ".sam",'wb',0) as input_file:
with open(SAMPLE+ "."+ TARGET+ ".bam",'wb',0) as output_file:
cmd = Popen([Dir+ "samtools-1.1/samtools view",'-bS'],
stdin=(input_file), stdout=(output_file), shell=True)
in Python and am still not getting samtools to convert a .sam to a .bam file. What am I doing wrong?
Abukamel is right, but in case you (or others) are wondering about your specific examples....
You're not too far off with your first attempt, just a few minor items:
Filenames should be in quotes
samtools reads from a named input file, not from stdin
You don't need "shell=True" since you're not using shell tricks like redirection
So you can do:
import subprocess
subprocess.call(["samtools", "view", "-bS", "aln.sam"],
stdout=open('aln.bam','w'))
Your second example has more or less the same issues, so would need to be changed to something like:
from subprocess import Popen
with open('aln.bam', 'wb',0) as output_file:
cmd = Popen(["samtools", "view",'-bS','aln.sam'],
stdout=(output_file))
You can pass execution to the shell by kwarg 'shell=True'
subprocess.call('samtools view -bS aln.sam > aln.bam', shell=True)

python subprocess.popen redirect to create a file

I've been searching for how to do this without any success. I've inherited a python script for performing an hourly backup on our database. The original script is too slow, so I'm trying a faster utility. My new command would look like this if typed into a shell:
pg_basebackup -h 127.0.0.1 -F t -X f -c fast -z -D - --username=postgres > db.backup.tgz
The problem is that the original script uses call(cmd) and it fails if the above is the cmd string. I've been looking for how to modify this to use popen but cannot find any examples where a file create redirect is used as in
>. The pg_basebackup as shown will output to stdout. The only way I've succeeded so far is to change -D - to -D some.file.tgz and then move the file to the archive, but I'd rather do this in one step.
Any ideas?
Jay
May be like this ?
with open("db.backup.tgz","a") as stdout:
p = subprocess.Popen(cmd_without_redirector, stdout=stdout, stderr=stdout, shell=True)
p.wait()
Hmmm... The pg_basebackup executable must be able to attach to that file. If I open the file in the manner you suggest, I don't know the correct syntax in python to be able to do that. If I try putting either " > " or " >> " in the string to call with cmd(), python pukes on it. That's my real problem that I'm not finding any guidance on.

Categories

Resources