Module torpido.tools.ffmpeg
Utility functions to run subprocess with generated FFmpeg queries. Function to build the commands live here.
Expand source code
"""
Utility functions to run subprocess with generated FFmpeg queries.
Function to build the commands live here.
"""
import subprocess
from torpido.exceptions import AudioStreamMissingException, FFmpegProcessException
from torpido.tools.logger import Log
def buildSplitCommand(inputFile, outputAudioFile):
"""
Creates a list for each bit of the command line to run
since it is a list the command line is secure and can
run with file names that are not formatted correctly.
or doesn't need any explicit formatting.
Parameters
----------
inputFile : str
input video file name and path
outputAudioFile : str
output audio file name and path
Returns
---------
_CMD
command line to pass to the subprocess
Examples
----------
The command created spits the video file into an audio file, The file paths
are kept same. The command goes like this
`ffmpeg -y -i input.mkv output.wav`
'-y' : FFmpeg option for 'yes override'. Override the output file it exists
'-i' : FFmpeg option for 'input file'. Input file can be multiple
"""
return [
'ffmpeg',
'-y',
'-i',
str(inputFile),
str(outputAudioFile)
]
def split(inputFile, outputAudioFile):
"""
Splits the input video file into audio for Audio Processing.
Helper function to run the generated command line with subprocess the stdout log is yielded to generate
the progress bar. Look into `io` for details
Parameters
----------
inputFile : str
name of the input video file
outputAudioFile : str
name of the output audio file
Yields
-------
str
yields std out logs in string
"""
command = buildSplitCommand(inputFile, outputAudioFile)
run = subprocess.Popen(args=command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
for stdout in iter(run.stdout.readline, ""):
yield stdout
run.stdout.close()
if run.wait():
Log.e("The splitting process has caused an error.")
raise AudioStreamMissingException
def buildMergeCommand(videoFile, audioFile, outputFile, timestamps):
"""
Building a complex filter
command line to clip portions based on the timestamps, the copies used
to trim some portion depend on the length of the timestamps since that
will define the number of the trims
Parameters
----------
videoFile : str
original input video file
audioFile : str
processed audio file (de-noised)
outputFile : str
final output video file edited by Torpido
timestamps : iterable
start and end timestamps of the video clips to trim
Returns
-------
str
generated string from the complex filter built
Examples
--------
The command line has following structure
`
ffmpeg -y -i input.mkv -i input.wav -filter_complex
"[0:v]split=2[vc1][vc2];
[vc1]trim=start=304:duration=10.567,setpts=PTS-STARTPTS[v1];
[vc2]trim=start=100:duration=10.789,setpts=PTS-STARTPTS[v2];
[1:a]asplit=2[ac1][ac2];
[ac1]atrim=start=0:duration=10.123,asetpts=PTS-STARTPTS[a1];
[ac2]atrim=start=304:duration=10,asetpts=PTS-STARTPTS[a2];
[v1][a1][v2][a2]concat=n=2:v=1:a=1[video][audio]"
-map "[video]" -map "[audio]" output_new.mkv
`
'-y' : FFmpeg option for 'yes override'. Override the output file it exists
'-i' : FFmpeg option for 'input file'. Input file to the command can be multiple
'-filter_complex' : create a complex filter
'split' : split option of filter to split the video stream into n ; here n=2
'trim' : trim option of filter to trim the video stream with
start= and duration=, also setpts:presentation points
'asplit' : audio stream split
'atrim' : audio stream trim
'concat' : concatenate input stream to output v=1:a=1 one video and one audio streams
'map' : map the labels of stream to the output file
'[]' : labels for each stream
"""
filterString = 'ffmpeg' + \
' -y' + \
' -i ' + \
str(videoFile) + \
' -i ' + \
str(audioFile) + \
' -filter_complex ' + \
'"[0:v]split=' + str(len(timestamps))
for i in range(len(timestamps)):
filterString += '[vc%d]' % i
filterString += '; '
for i in range(len(timestamps)):
startTime = timestamps[i][0]
endTime = timestamps[i][1]
filterString += '[vc%d]' % i
filterString += 'trim=start=%f:duration=%f,setpts=PTS-STARTPTS[v%d]; ' \
% (startTime, (endTime - startTime), int(i))
filterString += '[1:a]asplit=' + str(len(timestamps))
for i in range(len(timestamps)):
filterString += '[ac%d]' % i
filterString += '; '
for i in range(len(timestamps)):
startTime = timestamps[i][0]
endTime = timestamps[i][1]
filterString += '[ac%d]' % i
filterString += 'atrim=start=%f:duration=%f,asetpts=PTS-STARTPTS[a%d]; ' \
% (startTime, (endTime - startTime), int(i))
for i in range(len(timestamps)):
filterString += '[v%d][a%d]' % (i, i)
filterString += 'concat=n=%d:v=1:a=1[video][audio]"' % (len(timestamps))
filterString += ' -map' + \
' "[video]"' + \
' -map' + \
' "[audio]" ' + \
str(outputFile)
return filterString
def merge(videoFile, audioFile, outputFile, timestamps):
"""
Generate the command for complex filter according to the timestamps and encode the output video. Merge the
input video file and replace the audio stream with the de-noised audio stream
Notes
------
For using `string` as a command line it is very necessary to add shell=True in the Popen
function argument or it won't work
Use `stderr=subprocess.STDOUT` to stop printing the command output even though nothing
is printing
Parameters
----------
videoFile : str
input video file
audioFile : str
de-noised audio file
outputFile : str
final output video file
timestamps : list
list of clip time stamps with start and end times
Yields
-------
str
continuous std out logs
"""
# print(f"[TIMESTAMPS] timestamps : {timestamps}")
command = buildMergeCommand(videoFile, audioFile, outputFile, timestamps)
# print(command)
run = subprocess.Popen(args=command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
for stdout in iter(run.stdout.readline, ""):
yield stdout
run.stdout.close()
if run.wait():
Log.e(f"The merging process has caused an error.")
raise FFmpegProcessException
Functions
def buildMergeCommand(videoFile, audioFile, outputFile, timestamps)
-
Building a complex filter command line to clip portions based on the timestamps, the copies used to trim some portion depend on the length of the timestamps since that will define the number of the trims
Parameters
videoFile
:str
- original input video file
audioFile
:str
- processed audio file (de-noised)
outputFile
:str
- final output video file edited by Torpido
timestamps
:iterable
- start and end timestamps of the video clips to trim
Returns
str
- generated string from the complex filter built
Examples
The command line has following structure
` ffmpeg -y -i input.mkv -i input.wav -filter_complex "[0:v]split=2[vc1][vc2]; [vc1]trim=start=304:duration=10.567,setpts=PTS-STARTPTS[v1]; [vc2]trim=start=100:duration=10.789,setpts=PTS-STARTPTS[v2];
[1:a]asplit=2[ac1][ac2]; [ac1]atrim=start=0:duration=10.123,asetpts=PTS-STARTPTS[a1]; [ac2]atrim=start=304:duration=10,asetpts=PTS-STARTPTS[a2];
[v1][a1][v2][a2]concat=n=2:v=1:a=1[video][audio]" -map "[video]" -map "[audio]" output_new.mkv `
'-y' : FFmpeg option for 'yes override'. Override the output file it exists '-i' : FFmpeg option for 'input file'. Input file to the command can be multiple '-filter_complex' : create a complex filter 'split' : split option of filter to split the video stream into n ; here n=2 'trim' : trim option of filter to trim the video stream with start= and duration=, also setpts:presentation points 'asplit' : audio stream split 'atrim' : audio stream trim 'concat' : concatenate input stream to output v=1:a=1 one video and one audio streams 'map' : map the labels of stream to the output file '[]' : labels for each stream
Expand source code
def buildMergeCommand(videoFile, audioFile, outputFile, timestamps): """ Building a complex filter command line to clip portions based on the timestamps, the copies used to trim some portion depend on the length of the timestamps since that will define the number of the trims Parameters ---------- videoFile : str original input video file audioFile : str processed audio file (de-noised) outputFile : str final output video file edited by Torpido timestamps : iterable start and end timestamps of the video clips to trim Returns ------- str generated string from the complex filter built Examples -------- The command line has following structure ` ffmpeg -y -i input.mkv -i input.wav -filter_complex "[0:v]split=2[vc1][vc2]; [vc1]trim=start=304:duration=10.567,setpts=PTS-STARTPTS[v1]; [vc2]trim=start=100:duration=10.789,setpts=PTS-STARTPTS[v2]; [1:a]asplit=2[ac1][ac2]; [ac1]atrim=start=0:duration=10.123,asetpts=PTS-STARTPTS[a1]; [ac2]atrim=start=304:duration=10,asetpts=PTS-STARTPTS[a2]; [v1][a1][v2][a2]concat=n=2:v=1:a=1[video][audio]" -map "[video]" -map "[audio]" output_new.mkv ` '-y' : FFmpeg option for 'yes override'. Override the output file it exists '-i' : FFmpeg option for 'input file'. Input file to the command can be multiple '-filter_complex' : create a complex filter 'split' : split option of filter to split the video stream into n ; here n=2 'trim' : trim option of filter to trim the video stream with start= and duration=, also setpts:presentation points 'asplit' : audio stream split 'atrim' : audio stream trim 'concat' : concatenate input stream to output v=1:a=1 one video and one audio streams 'map' : map the labels of stream to the output file '[]' : labels for each stream """ filterString = 'ffmpeg' + \ ' -y' + \ ' -i ' + \ str(videoFile) + \ ' -i ' + \ str(audioFile) + \ ' -filter_complex ' + \ '"[0:v]split=' + str(len(timestamps)) for i in range(len(timestamps)): filterString += '[vc%d]' % i filterString += '; ' for i in range(len(timestamps)): startTime = timestamps[i][0] endTime = timestamps[i][1] filterString += '[vc%d]' % i filterString += 'trim=start=%f:duration=%f,setpts=PTS-STARTPTS[v%d]; ' \ % (startTime, (endTime - startTime), int(i)) filterString += '[1:a]asplit=' + str(len(timestamps)) for i in range(len(timestamps)): filterString += '[ac%d]' % i filterString += '; ' for i in range(len(timestamps)): startTime = timestamps[i][0] endTime = timestamps[i][1] filterString += '[ac%d]' % i filterString += 'atrim=start=%f:duration=%f,asetpts=PTS-STARTPTS[a%d]; ' \ % (startTime, (endTime - startTime), int(i)) for i in range(len(timestamps)): filterString += '[v%d][a%d]' % (i, i) filterString += 'concat=n=%d:v=1:a=1[video][audio]"' % (len(timestamps)) filterString += ' -map' + \ ' "[video]"' + \ ' -map' + \ ' "[audio]" ' + \ str(outputFile) return filterString
def buildSplitCommand(inputFile, outputAudioFile)
-
Creates a list for each bit of the command line to run since it is a list the command line is secure and can run with file names that are not formatted correctly. or doesn't need any explicit formatting.
Parameters
inputFile
:str
- input video file name and path
outputAudioFile
:str
- output audio file name and path
Returns
_CMD
- command line to pass to the subprocess
Examples
The command created spits the video file into an audio file, The file paths are kept same. The command goes like this
ffmpeg -y -i input.mkv output.wav
'-y' : FFmpeg option for 'yes override'. Override the output file it exists '-i' : FFmpeg option for 'input file'. Input file can be multiple
Expand source code
def buildSplitCommand(inputFile, outputAudioFile): """ Creates a list for each bit of the command line to run since it is a list the command line is secure and can run with file names that are not formatted correctly. or doesn't need any explicit formatting. Parameters ---------- inputFile : str input video file name and path outputAudioFile : str output audio file name and path Returns --------- _CMD command line to pass to the subprocess Examples ---------- The command created spits the video file into an audio file, The file paths are kept same. The command goes like this `ffmpeg -y -i input.mkv output.wav` '-y' : FFmpeg option for 'yes override'. Override the output file it exists '-i' : FFmpeg option for 'input file'. Input file can be multiple """ return [ 'ffmpeg', '-y', '-i', str(inputFile), str(outputAudioFile) ]
def merge(videoFile, audioFile, outputFile, timestamps)
-
Generate the command for complex filter according to the timestamps and encode the output video. Merge the input video file and replace the audio stream with the de-noised audio stream
Notes
For using
string
as a command line it is very necessary to add shell=True in the Popen function argument or it won't workUse
stderr=subprocess.STDOUT
to stop printing the command output even though nothing is printingParameters
videoFile
:str
- input video file
audioFile
:str
- de-noised audio file
outputFile
:str
- final output video file
timestamps
:list
- list of clip time stamps with start and end times
Yields
str
- continuous std out logs
Expand source code
def merge(videoFile, audioFile, outputFile, timestamps): """ Generate the command for complex filter according to the timestamps and encode the output video. Merge the input video file and replace the audio stream with the de-noised audio stream Notes ------ For using `string` as a command line it is very necessary to add shell=True in the Popen function argument or it won't work Use `stderr=subprocess.STDOUT` to stop printing the command output even though nothing is printing Parameters ---------- videoFile : str input video file audioFile : str de-noised audio file outputFile : str final output video file timestamps : list list of clip time stamps with start and end times Yields ------- str continuous std out logs """ # print(f"[TIMESTAMPS] timestamps : {timestamps}") command = buildMergeCommand(videoFile, audioFile, outputFile, timestamps) # print(command) run = subprocess.Popen(args=command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) for stdout in iter(run.stdout.readline, ""): yield stdout run.stdout.close() if run.wait(): Log.e(f"The merging process has caused an error.") raise FFmpegProcessException
def split(inputFile, outputAudioFile)
-
Splits the input video file into audio for Audio Processing.
Helper function to run the generated command line with subprocess the stdout log is yielded to generate the progress bar. Look into
io
for detailsParameters
inputFile
:str
- name of the input video file
outputAudioFile
:str
- name of the output audio file
Yields
str
- yields std out logs in string
Expand source code
def split(inputFile, outputAudioFile): """ Splits the input video file into audio for Audio Processing. Helper function to run the generated command line with subprocess the stdout log is yielded to generate the progress bar. Look into `io` for details Parameters ---------- inputFile : str name of the input video file outputAudioFile : str name of the output audio file Yields ------- str yields std out logs in string """ command = buildSplitCommand(inputFile, outputAudioFile) run = subprocess.Popen(args=command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) for stdout in iter(run.stdout.readline, ""): yield stdout run.stdout.close() if run.wait(): Log.e("The splitting process has caused an error.") raise AudioStreamMissingException