@@ -34,17 +34,27 @@ def __init__(
3434 resizer : Optional [Resizer ] = None ,
3535 fps : Optional [int ] = None ,
3636 fps_eps : float = 0.1 ,
37+ cut_start_col : Optional [str ] = None ,
38+ cut_duration_col : Optional [str ] = None ,
39+ copy_stream : bool = False ,
40+ preset : Optional [str ] = None ,
41+ crf : Optional [int ] = None ,
42+ copy_audio_stream : bool = True ,
3743 pool_type : PoolOptions = 'threads' ,
3844 workers : int = 16 ,
3945 pbar : bool = True ,
40- preset : Optional [str ] = None ,
41- crf : Optional [int ] = None ,
42- copy_audio_stream : bool = True
4346 ):
4447 super ().__init__ (pool_type , workers , pbar )
4548 self .resizer = resizer
4649 self .fps = fps
4750 self .fps_eps = fps_eps
51+ self .cut_start_col = cut_start_col
52+ self .cut_duration_col = cut_duration_col
53+ if self .cut_duration_col or self .cut_start_col :
54+ assert self .cut_duration_col and self .cut_start_col , f"Both { self .cut_duration_col } and { self .cut_start_col } must be specified"
55+ self .copy_when_cut = copy_stream
56+ if self .copy_when_cut :
57+ assert self .copy_when_cut and not (self .fps or self .resizer ), "Copy stream can be used only for cutting videos"
4858
4959 self .preset = preset
5060 self .crf = crf
@@ -53,7 +63,7 @@ def __init__(
5363 self .default_args = ' ' .join (self .get_default_ffmpeg_args ())
5464
5565 assert is_ffmpeg_installed (), "Install ffmpeg first"
56- assert self .resizer or self .fps , "At least one transform should be specified"
66+ assert self .resizer or self .fps or self . cut_start_col , "At least one transform should be specified"
5767
5868 def get_default_ffmpeg_args (self ) -> list [str ]:
5969 args = []
@@ -72,6 +82,8 @@ def required_metadata(self) -> list[str]:
7282 meta += ['width' , 'height' ]
7383 if self .fps :
7484 meta += ['fps' ]
85+ if self .cut_duration_col and self .cut_start_col :
86+ meta += [self .cut_start_col , self .cut_duration_col ]
7587 return meta
7688
7789 @property
@@ -90,6 +102,7 @@ def modality(self) -> str:
90102 def _process_filepath (self , data : TransformsFileData ) -> TransformsFileData :
91103 filepath = data .filepath
92104 ext = filepath .split ('.' )[- 1 ]
105+ ffmpeg_args_start : list [str ] = []
93106 ffmpeg_args_map : dict [str , list [str ]] = {}
94107 result_metadata : dict [str , Any ] = {}
95108
@@ -110,10 +123,20 @@ def _process_filepath(self, data: TransformsFileData) -> TransformsFileData:
110123 video_fps = float (self .fps )
111124 result_metadata ['fps' ] = video_fps
112125
126+ if self .cut_start_col and self .cut_duration_col and data .metadata [self .cut_start_col ] is not None :
127+ start = data .metadata [self .cut_start_col ]
128+ cut_duration = data .metadata [self .cut_duration_col ]
129+ ffmpeg_args_start .append (f'-ss { start } ' )
130+ ffmpeg_args_map ['-t' ] = [str (cut_duration )]
131+ if self .copy_when_cut :
132+ ffmpeg_args_map ['-c' ] = ['copy' ]
133+ ffmpeg_args_map ['-avoid_negative_ts' ] = ['1' ]
134+
113135 if len (ffmpeg_args_map ) > 0 :
114136 args_str = convert_ffmpeg_args_to_str (ffmpeg_args_map )
137+ args_start_str = ' ' .join (ffmpeg_args_start )
115138 temp_filename = str (uuid .uuid4 ()) + '.' + ext
116- ffmpeg_command = f'ffmpeg -hide_banner -i { filepath } { args_str } { self .default_args } { temp_filename } -y'
139+ ffmpeg_command = f'ffmpeg -hide_banner { args_start_str } -i { filepath } { args_str } { self .default_args } { temp_filename } -y'
117140 subprocess .run (ffmpeg_command , shell = True , capture_output = True , check = True )
118141 shutil .move (temp_filename , filepath )
119142
0 commit comments