Update api/ltx_server.py
Browse files- api/ltx_server.py +79 -42
api/ltx_server.py
CHANGED
|
@@ -436,61 +436,98 @@ class VideoService:
|
|
| 436 |
return chunks
|
| 437 |
|
| 438 |
|
| 439 |
-
|
| 440 |
-
def _gerar_lista_com_transicoes(self, pasta: str, video_paths:
|
| 441 |
"""
|
| 442 |
-
Gera uma nova lista de vídeos
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
Args:
|
| 446 |
-
pasta: pasta de trabalho
|
| 447 |
-
video_paths: lista de caminhos de vídeos originais
|
| 448 |
-
crossfade_frames: quantidade de frames para transição
|
| 449 |
-
Returns:
|
| 450 |
-
List[str]: nova lista de caminhos de vídeos, incluindo transições
|
| 451 |
"""
|
|
|
|
|
|
|
|
|
|
| 452 |
nova_lista = []
|
| 453 |
-
|
| 454 |
-
pasta
|
| 455 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
|
|
|
|
|
|
|
|
|
| 462 |
if i == 0:
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
|
|
|
| 471 |
|
| 472 |
-
|
| 473 |
-
|
|
|
|
|
|
|
| 474 |
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
|
|
|
|
|
|
| 479 |
subprocess.run(cmd_fim, shell=True, check=True)
|
| 480 |
|
| 481 |
-
|
| 482 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
subprocess.run(cmd_inicio, shell=True, check=True)
|
| 484 |
|
| 485 |
-
|
| 486 |
-
|
| 487 |
-
|
| 488 |
-
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
|
|
|
|
| 494 |
return nova_lista
|
| 495 |
|
| 496 |
|
|
|
|
| 436 |
return chunks
|
| 437 |
|
| 438 |
|
| 439 |
+
|
| 440 |
+
def _gerar_lista_com_transicoes(self, pasta: str, video_paths: list[str], crossfade_frames: int = 8) -> list[str]:
|
| 441 |
"""
|
| 442 |
+
Gera uma nova lista de vídeos aplicando transições suaves (crossfade de N frames)
|
| 443 |
+
entre cada par de vídeos da lista original.
|
| 444 |
+
Mantém todos os arquivos na mesma pasta dos vídeos originais.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 445 |
"""
|
| 446 |
+
|
| 447 |
+
import os, subprocess
|
| 448 |
+
|
| 449 |
nova_lista = []
|
|
|
|
|
|
|
| 450 |
|
| 451 |
+
# 🔹 Filtrar apenas vídeos MP4 válidos
|
| 452 |
+
video_paths = [v for v in video_paths if v.endswith(".mp4") and os.path.isfile(v)]
|
| 453 |
+
if not video_paths:
|
| 454 |
+
raise ValueError("[ERRO] Nenhum vídeo MP4 válido encontrado para processar.")
|
| 455 |
|
| 456 |
+
print(f"[DEBUG] Gerando transições entre {len(video_paths)} vídeos...")
|
| 457 |
+
|
| 458 |
+
# 🔹 Iterar pelos vídeos originais
|
| 459 |
+
for i, video_atual in enumerate(video_paths):
|
| 460 |
+
base_nome = os.path.splitext(os.path.basename(video_atual))[0]
|
| 461 |
+
print(f"[DEBUG] Processando vídeo {i+1}/{len(video_paths)}: {base_nome}")
|
| 462 |
+
|
| 463 |
+
# --- PRIMEIRO VÍDEO ---
|
| 464 |
if i == 0:
|
| 465 |
+
# 1️⃣ Podar o final (remover últimos frames)
|
| 466 |
+
video_podado_fim = os.path.join(pasta, f"{base_nome}_podado_fim.mp4")
|
| 467 |
+
cmd_trim = (
|
| 468 |
+
f'ffmpeg -y -i "{video_atual}" -vf "trim=0:-{crossfade_frames},setpts=PTS-STARTPTS" '
|
| 469 |
+
f'"{video_podado_fim}"'
|
| 470 |
+
)
|
| 471 |
+
subprocess.run(cmd_trim, shell=True, check=True)
|
| 472 |
+
nova_lista.append(video_podado_fim)
|
| 473 |
+
print(f"[DEBUG] Adicionado {video_podado_fim}")
|
| 474 |
|
| 475 |
+
# --- INTERMEDIÁRIO ---
|
| 476 |
+
if i < len(video_paths) - 1:
|
| 477 |
+
proximo_video = video_paths[i + 1]
|
| 478 |
+
prox_nome = os.path.splitext(os.path.basename(proximo_video))[0]
|
| 479 |
|
| 480 |
+
# 2️⃣ Extrair últimos frames do atual
|
| 481 |
+
fim_tmp = os.path.join(pasta, f"{base_nome}_fim_{i}.mp4")
|
| 482 |
+
cmd_fim = (
|
| 483 |
+
f'ffmpeg -y -sseof -{crossfade_frames / 24:.3f} -i "{video_atual}" '
|
| 484 |
+
f'-vf "setpts=PTS-STARTPTS" -an "{fim_tmp}"'
|
| 485 |
+
)
|
| 486 |
subprocess.run(cmd_fim, shell=True, check=True)
|
| 487 |
|
| 488 |
+
# 3️⃣ Extrair primeiros frames do próximo
|
| 489 |
+
inicio_tmp = os.path.join(pasta, f"{prox_nome}_inicio_{i+1}.mp4")
|
| 490 |
+
cmd_inicio = (
|
| 491 |
+
f'ffmpeg -y -i "{proximo_video}" -vf "trim=0:{crossfade_frames},setpts=PTS-STARTPTS" '
|
| 492 |
+
f'-an "{inicio_tmp}"'
|
| 493 |
+
)
|
| 494 |
subprocess.run(cmd_inicio, shell=True, check=True)
|
| 495 |
|
| 496 |
+
# 4️⃣ Gerar transição (crossfade)
|
| 497 |
+
transicao_path = os.path.join(pasta, f"transicao_{i+1}.mp4")
|
| 498 |
+
cmd_crossfade = (
|
| 499 |
+
f'ffmpeg -y -i "{fim_tmp}" -i "{inicio_tmp}" '
|
| 500 |
+
f'-filter_complex "xfade=transition=fade:duration={crossfade_frames/24:.3f}:offset=0" '
|
| 501 |
+
f'-c:v libx264 -pix_fmt yuv420p "{transicao_path}"'
|
| 502 |
+
)
|
| 503 |
+
subprocess.run(cmd_crossfade, shell=True, check=True)
|
| 504 |
+
|
| 505 |
+
nova_lista.append(transicao_path)
|
| 506 |
+
print(f"[DEBUG] Transição adicionada: {transicao_path}")
|
| 507 |
+
|
| 508 |
+
# --- VÍDEO INTERMEDIÁRIO (remover início e fim) ---
|
| 509 |
+
if i + 1 < len(video_paths) - 1:
|
| 510 |
+
video_podado_inicio_fim = os.path.join(pasta, f"{prox_nome}_podado_if.mp4")
|
| 511 |
+
cmd_trim_if = (
|
| 512 |
+
f'ffmpeg -y -i "{proximo_video}" -vf "trim={crossfade_frames}:-{crossfade_frames},setpts=PTS-STARTPTS" '
|
| 513 |
+
f'"{video_podado_inicio_fim}"'
|
| 514 |
+
)
|
| 515 |
+
subprocess.run(cmd_trim_if, shell=True, check=True)
|
| 516 |
+
nova_lista.append(video_podado_inicio_fim)
|
| 517 |
+
print(f"[DEBUG] Adicionado vídeo intermediário podado: {video_podado_inicio_fim}")
|
| 518 |
+
|
| 519 |
+
# --- ÚLTIMO VÍDEO ---
|
| 520 |
+
elif i + 1 == len(video_paths) - 1:
|
| 521 |
+
video_podado_inicio = os.path.join(pasta, f"{prox_nome}_podado_inicio.mp4")
|
| 522 |
+
cmd_trim_inicio = (
|
| 523 |
+
f'ffmpeg -y -i "{proximo_video}" -vf "trim={crossfade_frames},setpts=PTS-STARTPTS" '
|
| 524 |
+
f'"{video_podado_inicio}"'
|
| 525 |
+
)
|
| 526 |
+
subprocess.run(cmd_trim_inicio, shell=True, check=True)
|
| 527 |
+
nova_lista.append(video_podado_inicio)
|
| 528 |
+
print(f"[DEBUG] Adicionado último vídeo podado: {video_podado_inicio}")
|
| 529 |
|
| 530 |
+
print(f"[DEBUG] Nova lista final de {len(nova_lista)} arquivos criada.")
|
| 531 |
return nova_lista
|
| 532 |
|
| 533 |
|