Eueuiaa commited on
Commit
1e68ded
·
verified ·
1 Parent(s): 7d4b3e0

Update tools/video_encode_tool.py

Browse files
Files changed (1) hide show
  1. tools/video_encode_tool.py +62 -48
tools/video_encode_tool.py CHANGED
@@ -118,85 +118,99 @@ class VideoEncodeTool:
118
 
119
 
120
 
121
- def concatenate_videos(self, video_paths: List[str], output_path: str, workspace_dir: str, overlap: int=1) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  """
123
- Concatena múltiplos clipes de vídeo em um único arquivo,
124
- removendo o último frame de cada vídeo exceto o último.
125
  """
126
  if not video_paths:
127
  raise VideoToolError("Nenhum fragmento de vídeo fornecido para concatenação.")
128
 
129
  if len(video_paths) == 1:
130
  shutil.copy(video_paths[0], output_path)
131
- logger.info(f"Apenas um clipe fornecido. Copiado para '{output_path}'.")
132
  return output_path
133
 
134
- # Pasta temporária para cortes intermediários
135
- temp_dir = os.path.join(workspace_dir, "temp_cut_videos")
136
  os.makedirs(temp_dir, exist_ok=True)
137
-
138
  processed_videos = []
139
 
140
  try:
141
- for i, path in enumerate(video_paths):
142
- abs_path = os.path.abspath(path)
143
- # Verifica o número total de frames usando ffprobe
 
144
  probe_cmd = [
145
  'ffprobe', '-v', 'error', '-select_streams', 'v:0',
146
  '-count_frames', '-show_entries', 'stream=nb_read_frames',
147
- '-of', 'default=nokey=1:noprint_wrappers=1', abs_path
148
  ]
149
  result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
150
  total_frames = int(result.stdout.strip())
 
 
 
 
 
151
 
 
152
  if i < len(video_paths) - 1:
153
- # Remove o último frame do vídeo
154
- cut_frames = total_frames - overlap
155
- temp_output = os.path.join(temp_dir, f"cut_{i}.mp4")
156
-
157
- # Cria uma versão sem o último frame (mantendo codec e fps)
158
- cut_cmd = [
159
- 'ffmpeg', '-y', '-i', abs_path,
160
- '-vf', f'select=lt(n\\,{cut_frames})', # mantém apenas n < total_frames-1
161
- '-vsync', '0', '-c:v', 'libx264', '-preset', 'fast', '-crf', '18',
162
- '-an', temp_output
163
- ]
164
- subprocess.run(cut_cmd, check=True, capture_output=True, text=True)
165
- processed_videos.append(temp_output)
166
- logger.debug(f"Removido último frame do vídeo {i} ({cut_frames}/{total_frames}).")
167
  else:
168
- # Último vídeo permanece intacto
169
- processed_videos.append(abs_path)
170
 
171
- # Cria o arquivo de concatenação
172
  list_file_path = os.path.join(workspace_dir, f"concat_list_{int(time.time())}.txt")
173
  with open(list_file_path, 'w', encoding='utf-8') as f:
174
- for p in processed_videos:
175
- f.write(f"file '{os.path.abspath(p)}'\n")
176
-
177
- # Executa concatenação final
178
- cmd_list = [
179
- 'ffmpeg', '-y', '-f', 'concat', '-safe', '0',
180
- '-i', list_file_path, '-c', 'copy', output_path
181
- ]
182
- logger.info(f"Concatenando {len(processed_videos)} clipes em '{output_path}'...")
183
- subprocess.run(cmd_list, check=True, capture_output=True, text=True)
184
- logger.info("Concatenação FFmpeg bem-sucedida.")
185
  return output_path
186
 
187
  except subprocess.CalledProcessError as e:
188
- logger.error(f"Erro ao processar vídeos: {e.stderr}")
189
- raise VideoToolError("Falha durante concatenação dos vídeos.")
190
  finally:
191
  # Limpa arquivos temporários
192
- for f in os.listdir(temp_dir):
193
- os.remove(os.path.join(temp_dir, f))
194
- os.rmdir(temp_dir)
195
-
196
- list_file_path = os.path.join(workspace_dir, f"concat_list_{int(time.time())}.txt")
197
- if os.path.exists(list_file_path):
 
 
198
  os.remove(list_file_path)
199
-
200
 
201
  def concatenate_videos2(self, video_paths: List[str], output_path: str, workspace_dir: str) -> str:
202
  """
 
118
 
119
 
120
 
121
+ import os
122
+ import subprocess
123
+ import shutil
124
+ import time
125
+ from typing import List
126
+ import logging
127
+
128
+ logger = logging.getLogger(__name__)
129
+
130
+ class VideoToolError(Exception):
131
+ pass
132
+
133
+ class VideoEditor:
134
+ def concatenate_videos(self, video_paths: List[str], output_path: str, workspace_dir: str, star:int=0, overlap:int=1) -> str:
135
  """
136
+ Concatena múltiplos vídeos MP4, removendo exatamente o último frame
137
+ de cada vídeo, exceto o último, usando trim por frame.
138
  """
139
  if not video_paths:
140
  raise VideoToolError("Nenhum fragmento de vídeo fornecido para concatenação.")
141
 
142
  if len(video_paths) == 1:
143
  shutil.copy(video_paths[0], output_path)
144
+ logger.info(f"[Concat] Apenas um clipe fornecido. Copiado para '{output_path}'.")
145
  return output_path
146
 
147
+ temp_dir = os.path.join(workspace_dir, "temp_trimmed_videos")
 
148
  os.makedirs(temp_dir, exist_ok=True)
 
149
  processed_videos = []
150
 
151
  try:
152
+ for i, base in enumerate(video_paths):
153
+ abs_base = os.path.abspath(base)
154
+
155
+ # Obtém número total de frames via ffprobe
156
  probe_cmd = [
157
  'ffprobe', '-v', 'error', '-select_streams', 'v:0',
158
  '-count_frames', '-show_entries', 'stream=nb_read_frames',
159
+ '-of', 'default=nokey=1:noprint_wrappers=1', abs_base
160
  ]
161
  result = subprocess.run(probe_cmd, capture_output=True, text=True, check=True)
162
  total_frames = int(result.stdout.strip())
163
+ logger.debug(f"[Trim] {os.path.basename(base)} → total_frames={total_frames}")
164
+
165
+ # Define limites de corte
166
+ start_frame = start
167
+ end_frame = total_frames if i == len(video_paths) - 1 else total_frames - overlap
168
 
169
+ # Se for o último vídeo, não corta o frame final
170
  if i < len(video_paths) - 1:
171
+ video_podado = os.path.join(temp_dir, f"cut_{i}.mp4")
172
+ cmd_fim = (
173
+ f'ffmpeg -y -hide_banner -loglevel error -i "{abs_base}" '
174
+ f'-vf "trim=start_frame={start_frame}:end_frame={end_frame},setpts=PTS-STARTPTS" '
175
+ f'-an "{video_podado}"'
176
+ )
177
+ logger.debug(f"[CmdTrim] {cmd_fim}")
178
+ subprocess.run(cmd_fim, shell=True, check=True)
179
+ processed_videos.append(video_podado)
180
+ logger.debug(f"[TrimOK] {os.path.basename(base)} → -1 frame ({end_frame}/{total_frames})")
 
 
 
 
181
  else:
182
+ processed_videos.append(abs_base)
 
183
 
184
+ # Cria lista para concatenação
185
  list_file_path = os.path.join(workspace_dir, f"concat_list_{int(time.time())}.txt")
186
  with open(list_file_path, 'w', encoding='utf-8') as f:
187
+ for path in processed_videos:
188
+ f.write(f"file '{os.path.abspath(path)}'\n")
189
+
190
+ # Concat final
191
+ cmd_concat = (
192
+ f'ffmpeg -y -hide_banner -loglevel error -f concat -safe 0 '
193
+ f'-i "{list_file_path}" -c copy "{output_path}"'
194
+ )
195
+ logger.info(f"[Concat] Executando concatenação final: {cmd_concat}")
196
+ subprocess.run(cmd_concat, shell=True, check=True)
197
+ logger.info("[ConcatOK] Concatenação concluída com sucesso.")
198
  return output_path
199
 
200
  except subprocess.CalledProcessError as e:
201
+ logger.error(f"[ConcatERR] Erro FFmpeg: {e}")
202
+ raise VideoToolError("Falha durante a concatenação de vídeos.")
203
  finally:
204
  # Limpa arquivos temporários
205
+ if os.path.exists(temp_dir):
206
+ for f in os.listdir(temp_dir):
207
+ try:
208
+ os.remove(os.path.join(temp_dir, f))
209
+ except Exception:
210
+ pass
211
+ os.rmdir(temp_dir)
212
+ if 'list_file_path' in locals() and os.path.exists(list_file_path):
213
  os.remove(list_file_path)
 
214
 
215
  def concatenate_videos2(self, video_paths: List[str], output_path: str, workspace_dir: str) -> str:
216
  """