Carlos s
commited on
Update api/ltx_server.py
Browse files- api/ltx_server.py +28 -35
api/ltx_server.py
CHANGED
|
@@ -437,46 +437,39 @@ class VideoService:
|
|
| 437 |
|
| 438 |
|
| 439 |
|
| 440 |
-
def
|
| 441 |
"""
|
| 442 |
-
Concatena
|
| 443 |
-
|
|
|
|
|
|
|
|
|
|
| 444 |
"""
|
| 445 |
-
if len(
|
| 446 |
-
raise ValueError("
|
| 447 |
-
|
| 448 |
-
filter_parts = []
|
| 449 |
-
concat_sequence = []
|
| 450 |
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
for i in range(len(mp4_list) - 1):
|
| 457 |
-
filter_parts.append(
|
| 458 |
-
f"[v{i}]trim=0:-{crossfade_frames},setpts=PTS-STARTPTS[v{i}pre];"
|
| 459 |
-
f"[v{i}]trim=-{crossfade_frames},setpts=PTS-STARTPTS[v{i}fade];"
|
| 460 |
-
f"[v{i+1}]trim=0:{crossfade_frames},setpts=PTS-STARTPTS[v{i+1}fade];"
|
| 461 |
-
f"[v{i}fade][v{i+1}fade]blend=all_expr='A*(1-T/{crossfade_frames})+B*(T/{crossfade_frames})'[xf{i}]"
|
| 462 |
-
)
|
| 463 |
-
concat_sequence.append(f"[v{i}pre][xf{i}]")
|
| 464 |
|
| 465 |
-
|
| 466 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
filter_complex = ";".join(filter_parts) + ";" + concat_str + f"concat=n={len(concat_sequence)}:v=1:a=0[v]"
|
| 471 |
|
| 472 |
-
#
|
| 473 |
-
|
| 474 |
-
cmd = f"ffmpeg -y {inputs} -filter_complex \"{filter_complex}\" -map \"[v]\" -c:v libx264 -pix_fmt yuv420p '{out_path}'"
|
| 475 |
-
|
| 476 |
-
print("[DEBUG] Executando FFmpeg:\n", cmd)
|
| 477 |
-
subprocess.run(cmd, shell=True, check=True)
|
| 478 |
-
print("✅ Vídeo final gerado:", out_path)
|
| 479 |
-
|
| 480 |
|
| 481 |
|
| 482 |
def generate(
|
|
@@ -708,7 +701,7 @@ class VideoService:
|
|
| 708 |
|
| 709 |
final_concat = os.path.join(results_dir, f"concat_fim_{used_seed}.mp4")
|
| 710 |
#self._concat_mp4s_no_reencode(partes_mp4, final_concat)
|
| 711 |
-
self.
|
| 712 |
partes_mp4,
|
| 713 |
final_concat,
|
| 714 |
crossfade_frames=8,
|
|
|
|
| 437 |
|
| 438 |
|
| 439 |
|
| 440 |
+
def _concat_crossfade_cascade(self, videos, output_path, crossfade_duration=8):
|
| 441 |
"""
|
| 442 |
+
Concatena vídeos em cascata com crossfade.
|
| 443 |
+
|
| 444 |
+
:param videos: lista de caminhos de vídeos
|
| 445 |
+
:param output_path: caminho final do vídeo concatenado
|
| 446 |
+
:param crossfade_duration: duração do crossfade em frames
|
| 447 |
"""
|
| 448 |
+
if len(videos) < 2:
|
| 449 |
+
raise ValueError("Precisa de pelo menos 2 vídeos para concatenar")
|
|
|
|
|
|
|
|
|
|
| 450 |
|
| 451 |
+
temp_video = videos[0]
|
| 452 |
+
|
| 453 |
+
for i in range(1, len(videos)):
|
| 454 |
+
next_video = videos[i]
|
| 455 |
+
tmp_output = f"/tmp/cascade_{i}.mp4"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
|
| 457 |
+
cmd = f"""
|
| 458 |
+
ffmpeg -y -i "{temp_video}" -i "{next_video}" -filter_complex "
|
| 459 |
+
[0:v]trim=0:-{crossfade_duration},setpts=PTS-STARTPTS[v0pre];
|
| 460 |
+
[0:v]trim=-{crossfade_duration},setpts=PTS-STARTPTS[v0fade];
|
| 461 |
+
[1:v]trim=0:{crossfade_duration},setpts=PTS-STARTPTS[v1fade];
|
| 462 |
+
[v0fade][v1fade]blend=all_expr='A*(1-T/{crossfade_duration})+B*(T/{crossfade_duration})'[xf];
|
| 463 |
+
[0:v]trim=0:-{crossfade_duration},setpts=PTS-STARTPTS[v0start];
|
| 464 |
+
[1:v]trim={crossfade_duration}:,setpts=PTS-STARTPTS[v1end];
|
| 465 |
+
[v0start][xf][v1end]concat=n=3:v=1:a=0[v]" -map "[v]" -c:v libx264 -pix_fmt yuv420p "{tmp_output}"
|
| 466 |
+
"""
|
| 467 |
|
| 468 |
+
subprocess.run(cmd, shell=True, check=True)
|
| 469 |
+
temp_video = tmp_output # próximo loop concatena sobre este
|
|
|
|
| 470 |
|
| 471 |
+
# Renomeia o último temporário como saída final
|
| 472 |
+
os.rename(temp_video, output_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 473 |
|
| 474 |
|
| 475 |
def generate(
|
|
|
|
| 701 |
|
| 702 |
final_concat = os.path.join(results_dir, f"concat_fim_{used_seed}.mp4")
|
| 703 |
#self._concat_mp4s_no_reencode(partes_mp4, final_concat)
|
| 704 |
+
self._concat_crossfade_cascade(
|
| 705 |
partes_mp4,
|
| 706 |
final_concat,
|
| 707 |
crossfade_frames=8,
|