Update api/ltx_server.py
Browse files- api/ltx_server.py +58 -2
api/ltx_server.py
CHANGED
|
@@ -435,10 +435,66 @@ class VideoService:
|
|
| 435 |
print("================PODA CAUSAL=================")
|
| 436 |
return chunks
|
| 437 |
|
| 438 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
|
| 440 |
|
| 441 |
-
def
|
| 442 |
"""
|
| 443 |
Concatena vídeos em cascata com crossfade, usando FFmpeg.
|
| 444 |
|
|
|
|
| 435 |
print("================PODA CAUSAL=================")
|
| 436 |
return chunks
|
| 437 |
|
| 438 |
+
|
| 439 |
+
def _concat_crossfade_cascade(self, video_paths: List[str], crossfade_frames: int = 8, output_path: str = "/tmp/final_output.mp4"):
|
| 440 |
+
"""
|
| 441 |
+
Concatena uma lista de vídeos aplicando crossfade de 'crossfade_frames' entre cada par.
|
| 442 |
+
Args:
|
| 443 |
+
video_paths: lista de caminhos dos vídeos a concatenar
|
| 444 |
+
crossfade_frames: quantidade de frames para o crossfade
|
| 445 |
+
output_path: caminho do vídeo final gerado
|
| 446 |
+
"""
|
| 447 |
+
if not video_paths or len(video_paths) == 1:
|
| 448 |
+
# Apenas copiar se houver 1 ou nenhum vídeo
|
| 449 |
+
if video_paths:
|
| 450 |
+
subprocess.run(f"cp '{video_paths[0]}' '{output_path}'", shell=True, check=True)
|
| 451 |
+
return output_path
|
| 452 |
+
|
| 453 |
+
# Lista temporária de vídeos intermediários
|
| 454 |
+
temp_videos = []
|
| 455 |
+
|
| 456 |
+
# Começamos com o primeiro vídeo
|
| 457 |
+
prev_video = video_paths[0]
|
| 458 |
+
|
| 459 |
+
for i in range(1, len(video_paths)):
|
| 460 |
+
next_video = video_paths[i]
|
| 461 |
+
|
| 462 |
+
# Cria arquivo temporário para resultado do crossfade
|
| 463 |
+
temp_out = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
|
| 464 |
+
temp_out_path = temp_out.name
|
| 465 |
+
temp_out.close()
|
| 466 |
+
|
| 467 |
+
# Comando FFmpeg
|
| 468 |
+
cmd = f"""
|
| 469 |
+
ffmpeg -y -i "{prev_video}" -i "{next_video}" -filter_complex "
|
| 470 |
+
[0:v]trim=0:-{crossfade_frames},setpts=PTS-STARTPTS[v_prev_main];
|
| 471 |
+
[0:v]trim=-{crossfade_frames},setpts=PTS-STARTPTS[v_prev_fade];
|
| 472 |
+
[1:v]trim=0:{crossfade_frames},setpts=PTS-STARTPTS[v_next_fade];
|
| 473 |
+
[1:v]trim={crossfade_frames}:,setpts=PTS-STARTPTS[v_next_main];
|
| 474 |
+
[v_prev_fade][v_next_fade]blend=all_expr='A*(1-T/{crossfade_frames})+B*(T/{crossfade_frames})'[crossfade];
|
| 475 |
+
[v_prev_main][crossfade][v_next_main]concat=n=3:v=1:a=0[v]
|
| 476 |
+
" -map "[v]" -c:v libx264 -pix_fmt yuv420p "{temp_out_path}"
|
| 477 |
+
"""
|
| 478 |
+
|
| 479 |
+
# Executa FFmpeg
|
| 480 |
+
subprocess.run(cmd, shell=True, check=True)
|
| 481 |
+
|
| 482 |
+
# Atualiza prev_video para o próximo crossfade
|
| 483 |
+
prev_video = temp_out_path
|
| 484 |
+
temp_videos.append(temp_out_path)
|
| 485 |
+
|
| 486 |
+
# Move o último vídeo processado para o destino final
|
| 487 |
+
os.rename(prev_video, output_path)
|
| 488 |
+
|
| 489 |
+
# Remove vídeos temporários antigos
|
| 490 |
+
for tmp in temp_videos[:-1]:
|
| 491 |
+
if os.path.exists(tmp):
|
| 492 |
+
os.remove(tmp)
|
| 493 |
+
|
| 494 |
+
return output_path
|
| 495 |
|
| 496 |
|
| 497 |
+
def _concat_crossfade_cascade1(self, video_paths: List[str], output_path: str, crossfade_frames: int = 8):
|
| 498 |
"""
|
| 499 |
Concatena vídeos em cascata com crossfade, usando FFmpeg.
|
| 500 |
|