1- """Frame-based cutting/trimming/splicing of audio with VapourSynth."""
1+ """Frame-based cutting/trimming/splicing of audio with VapourSynth and FFmpeg ."""
22__all__ = ['eztrim' ]
33__author__ = 'Dave <orangechannel@pm.me>'
4- __date__ = '26 July 2020'
4+ __date__ = '29 July 2020'
55__credits__ = """AzraelNewtype, for the original audiocutter.py.
66Ricardo Constantino (wiiaboo), for vfr.py from which this was inspired.
77doop, for explaining the use of None for empty slicing
88"""
9- __version__ = '5.0.0 '
9+ __version__ = '5.0.1 '
1010
1111import fractions
12- import mimetypes
1312import os
1413import pathlib
1514import subprocess
@@ -65,6 +64,8 @@ def eztrim(clip: vs.VideoNode,
6564 ``src[15]`` must be entered as ``trims=(15, 16)``.
6665 :param audio_file: A string or path-like object refering to the source audio file's location
6766 (i.e. '/path/to/audio_file.ext').
67+ If the extension is not recognized as a valid audio file extension for FFmpeg's encoders,
68+ the audio will be re-encoded to WAV losslessly.
6869 :param outfile: Either a filename 'out.ext' or a full path '/path/to/out.ext'
6970 that will be used for the trimmed audio file.
7071 The extension will be automatically inserted for you,
@@ -82,17 +83,40 @@ def eztrim(clip: vs.VideoNode,
8283 else :
8384 if not os .path .isfile (audio_file ):
8485 raise FileNotFoundError (f"eztrim: { audio_file } not found" )
85- if not mimetypes .types_map [os .path .splitext (audio_file )[- 1 ]].startswith ('audio/' ):
86- raise ValueError (f"{ audio_file } does not seem to be an audio file; "
87- f"try to extract the audio track first if it is in a container" )
86+
87+ audio_file_name , audio_file_ext = os .path .splitext (audio_file )
88+ ffmpeg_valid_encoder_extensions = {
89+ '.aac' , '.m4a' , '.adts' ,
90+ '.ac3' ,
91+ '.alac' , '.caf' ,
92+ '.dca' , '.dts' ,
93+ '.eac3' ,
94+ '.flac' ,
95+ '.gsm' ,
96+ '.mlp' ,
97+ '.mp2' , '.mp3' , '.mpga' ,
98+ '.opus' , '.spx' , '.ogg' , '.oga'
99+ '.pcm' , '.raw' ,
100+ '.sbc' ,
101+ '.thd' ,
102+ '.tta' ,
103+ '.wav' ,
104+ '.wma' ,
105+ }
106+ if audio_file_ext not in ffmpeg_valid_encoder_extensions :
107+ warn (f"{ audio_file_ext } is not a supported extension by FFmpeg's audio encoders, re-encoding to WAV" , Warning )
108+ audio_file_ext = '.wav'
109+ else :
110+ codec_args = ['-c:a' , 'copy' ]
88111
89112 if outfile is None :
90- outfile = os . path . splitext ( audio_file )[ 0 ] + '_cut' + os . path . splitext ( audio_file )[ - 1 ]
113+ outfile = audio_file_name + '_cut' + audio_file_ext
91114 elif not os .path .splitext (outfile )[1 ]:
92- outfile += os .path .splitext (audio_file )[- 1 ]
93- elif os .path .splitext (audio_file )[- 1 ] != os .path .splitext (outfile )[- 1 ]:
94- outfile = os .path .splitext (outfile )[0 ] + os .path .splitext (audio_file )[- 1 ]
95- elif os .path .isfile (outfile ):
115+ outfile += audio_file_ext
116+ elif os .path .splitext (outfile )[- 1 ] != audio_file_ext :
117+ outfile = os .path .splitext (outfile )[0 ] + audio_file_ext
118+
119+ if os .path .isfile (outfile ):
96120 raise FileExistsError (f"eztrim: { outfile } already exists" )
97121
98122 if ffmpeg_path is None :
@@ -103,7 +127,7 @@ def eztrim(clip: vs.VideoNode,
103127 try :
104128 args = ['ffmpeg' , '-version' ]
105129 if subprocess .run (args , stdout = subprocess .PIPE , text = True ).stdout .split ()[0 ] != 'ffmpeg' :
106- raise FileNotFoundError ("ffmpeg executable not working properly" )
130+ raise ValueError ("ffmpeg executable not working properly" )
107131 except FileNotFoundError :
108132 raise FileNotFoundError ("ffmpeg executable not found in PATH" ) from None
109133
@@ -156,28 +180,28 @@ def eztrim(clip: vs.VideoNode,
156180 ffmpeg_silence = [str (ffmpeg_path ), '-hide_banner' , '-loglevel' , '16' ] if quiet else [str (ffmpeg_path ), '-hide_banner' ]
157181
158182 if len (cut_ts_s ) == 1 :
159- args = ffmpeg_silence + ['-i' , audio_file , '-vn' , '-ss' , cut_ts_s [0 ], '-to' , cut_ts_e [0 ], '-c:a' , 'copy' , outfile ]
183+ args = ffmpeg_silence + ['-i' , audio_file , '-vn' , '-ss' , cut_ts_s [0 ], '-to' , cut_ts_e [0 ]] + codec_args + [ outfile ]
160184 run (args )
161185 return
162186
163187 times = [[s , e ] for s , e in zip (cut_ts_s , cut_ts_e )]
164- if os .path .isfile ('_temp_concat .txt' ):
165- raise ValueError ("_temp_concat .txt already exists, quitting" )
188+ if os .path .isfile ('_acsuite_temp_concat .txt' ):
189+ raise ValueError ("_acsuite_temp_concat .txt already exists, quitting" )
166190 else :
167- concat_file = open ('_temp_concat .txt' , 'w' )
191+ concat_file = open ('_acsuite_temp_concat .txt' , 'w' )
168192 temp_filelist = []
169193 for key , time in enumerate (times ):
170- outfile_tmp = f'_temp_output_ { key } ' + os .path .splitext (outfile )[- 1 ]
194+ outfile_tmp = f'_acsuite_temp_output_ { key } ' + os .path .splitext (outfile )[- 1 ]
171195 concat_file .write (f"file { outfile_tmp } \n " )
172196 temp_filelist .append (outfile_tmp )
173- args = ffmpeg_silence + ['-i' , audio_file , '-vn' , '-ss' , time [0 ], '-to' , time [1 ], '-c:a' , 'copy' , outfile_tmp ]
197+ args = ffmpeg_silence + ['-i' , audio_file , '-vn' , '-ss' , time [0 ], '-to' , time [1 ]] + codec_args + [ outfile_tmp ]
174198 run (args )
175199
176200 concat_file .close ()
177- args = ffmpeg_silence + ['-f' , 'concat' , '-i' , '_temp_concat .txt' , '-c' , 'copy' , outfile ]
201+ args = ffmpeg_silence + ['-f' , 'concat' , '-i' , '_acsuite_temp_concat .txt' , '-c' , 'copy' , outfile ]
178202 run (args )
179203
180- os .remove ('_temp_concat .txt' )
204+ os .remove ('_acsuite_temp_concat .txt' )
181205 for file in temp_filelist :
182206 os .remove (file )
183207
0 commit comments