EuuIia commited on
Commit
a37a873
·
verified ·
1 Parent(s): afbc599

Update api/ltx_server.py

Browse files
Files changed (1) hide show
  1. api/ltx_server.py +28 -61
api/ltx_server.py CHANGED
@@ -436,91 +436,58 @@ class VideoService:
436
  return chunks
437
 
438
 
 
 
 
439
  def _concat_crossfade_videos_por_frames(self, mp4_list, out_path, fps=24, crossfade_frames=8):
440
  """
441
- Concatena múltiplos vídeos MP4 aplicando crossfade (blend) controlado por número de frames.
442
  Não inclui áudio.
443
-
444
  Args:
445
  mp4_list (List[str]): Lista de vídeos a concatenar.
446
  out_path (str): Caminho do vídeo final.
447
- fps (int): Taxa de quadros (todos devem ter o mesmo FPS).
448
- crossfade_frames (int): Número de frames usados no fade entre vídeos consecutivos.
449
  """
450
  if len(mp4_list) < 2:
451
  raise ValueError("Forneça ao menos dois vídeos para concatenar com crossfade.")
452
-
453
  inputs = " ".join([f"-i '{v}'" for v in mp4_list])
454
  filter_parts = []
455
  concat_refs = []
456
 
 
457
  for i in range(len(mp4_list)):
458
- v = f"[{i}:v]"
459
- filter_parts.append(f"{v}setpts=PTS-STARTPTS[v{i}]")
460
 
461
- # Agora criamos os blends entre pares consecutivos
462
  for i in range(len(mp4_list) - 1):
463
- a = f"[v{i}]"
464
- b = f"[v{i+1}]"
465
-
466
- fade = f"[v{i}b{i+1}]blend=all_expr='A*(1-T/{crossfade_frames})+B*(T/{crossfade_frames})'[xf{i}]"
467
  filter_parts.append(
468
- f"{a}trim=end_frame={crossfade_frames},setpts=PTS-STARTPTS[v{i}pre];"
469
- f"{a}trim=start_frame={crossfade_frames},setpts=PTS-STARTPTS[v{i}fade];"
470
- f"{b}trim=end_frame={crossfade_frames},setpts=PTS-STARTPTS[v{i+1}fade];"
471
- f"{a}trim=end_frame={crossfade_frames},setpts=PTS-STARTPTS[v{i}pre];"
472
- f"[v{i}fade][v{i+1}fade]{fade};"
473
  )
474
  concat_refs.append(f"[v{i}pre][xf{i}]")
475
 
476
- # Último vídeo (sem blend)
477
- concat_refs.append(f"[v{len(mp4_list) - 1}]")
478
 
479
- filter_complex = (
480
- ";".join(filter_parts)
481
- + ";"
482
- + "".join(concat_refs)
483
- + f"concat=n={len(mp4_list) * 2 - 1}:v=1:a=0[v]"
484
- )
485
 
486
- cmd = (
487
- f"ffmpeg -y {inputs} -filter_complex \"{filter_complex}\" "
488
- f"-map \"[v]\" -c:v libx264 -pix_fmt yuv420p \"{out_path}\""
489
- )
490
 
491
- print(f"[DEBUG] Crossfade concat:\n{cmd}\n")
492
 
493
- args = shlex.split(cmd) # transforma a string em lista de args
494
- subprocess.run(args, shell=False, check=True)
495
-
496
- print(f"✅ Vídeo final criado: {out_path}")
497
-
498
-
499
- def _concat_mp4s_no_reencode(self, mp4_list: List[str], out_path: str):
500
- """
501
- Concatena múltiplos MP4s sem reencode usando o demuxer do ffmpeg.
502
- ATENÇÃO: todos os arquivos precisam ter mesmo codec, fps, resolução etc.
503
- """
504
- if not mp4_list or len(mp4_list) < 2:
505
- raise ValueError("Forneça pelo menos dois arquivos MP4 para concatenar.")
506
-
507
- # Cria lista temporária para o ffmpeg
508
- with tempfile.NamedTemporaryFile("w", delete=False, suffix=".txt") as f:
509
- for mp4 in mp4_list:
510
- f.write(f"file '{os.path.abspath(mp4)}'\n")
511
- list_path = f.name
512
-
513
- cmd = f"ffmpeg -y -f concat -safe 0 -i {list_path} -c copy {out_path}"
514
- print(f"[DEBUG] Concat: {cmd}")
515
-
516
- try:
517
- subprocess.check_call(shlex.split(cmd))
518
- finally:
519
- try:
520
- os.remove(list_path)
521
- except Exception:
522
- pass
523
-
524
 
525
  def generate(
526
  self,
 
436
  return chunks
437
 
438
 
439
+
440
+
441
+
442
  def _concat_crossfade_videos_por_frames(self, mp4_list, out_path, fps=24, crossfade_frames=8):
443
  """
444
+ Concatena múltiplos vídeos MP4 aplicando crossfade visual (blend) controlado por número de frames.
445
  Não inclui áudio.
446
+
447
  Args:
448
  mp4_list (List[str]): Lista de vídeos a concatenar.
449
  out_path (str): Caminho do vídeo final.
450
+ fps (int): Frames por segundo dos vídeos.
451
+ crossfade_frames (int): Número de frames para a transição entre vídeos consecutivos.
452
  """
453
  if len(mp4_list) < 2:
454
  raise ValueError("Forneça ao menos dois vídeos para concatenar com crossfade.")
455
+
456
  inputs = " ".join([f"-i '{v}'" for v in mp4_list])
457
  filter_parts = []
458
  concat_refs = []
459
 
460
+ # Ajustar vídeos individuais
461
  for i in range(len(mp4_list)):
462
+ filter_parts.append(f"[{i}:v]setpts=PTS-STARTPTS[v{i}]")
 
463
 
464
+ # Criar blends (crossfade) entre pares consecutivos
465
  for i in range(len(mp4_list) - 1):
466
+ # Determine o início do fade do primeiro vídeo
467
+ # Primeiro vídeo: todos os frames menos os últimos crossfade_frames
 
 
468
  filter_parts.append(
469
+ f"[v{i}]trim=0:-{crossfade_frames},setpts=PTS-STARTPTS[v{i}pre];"
470
+ f"[v{i}]trim=-{crossfade_frames},setpts=PTS-STARTPTS[v{i}fade];"
471
+ f"[v{i+1}]trim=0:{crossfade_frames},setpts=PTS-STARTPTS[v{i+1}fade];"
472
+ f"[v{i}fade][v{i+1}fade]blend=all_expr='A*(1-T/{crossfade_frames})+B*(T/{crossfade_frames})'[xf{i}]"
 
473
  )
474
  concat_refs.append(f"[v{i}pre][xf{i}]")
475
 
476
+ # Último vídeo sem fade
477
+ concat_refs.append(f"[v{len(mp4_list)-1}]")
478
 
479
+ # Concat final
480
+ filter_complex = ";".join(filter_parts) + ";" + "".join(concat_refs) + f"concat=n={len(concat_refs)}:v=1:a=0[v]"
 
 
 
 
481
 
482
+ # Montar comando
483
+ cmd = f"ffmpeg -y {inputs} -filter_complex \"{filter_complex}\" -map \"[v]\" -c:v libx264 -pix_fmt yuv420p '{out_path}'"
 
 
484
 
485
+ print(f"[DEBUG] Executando FFmpeg:\n{cmd}\n")
486
 
487
+ # Executar comando via shell
488
+ subprocess.run(cmd, shell=True, check=True)
489
+
490
+ print(f"✅ Vídeo final gerado: {out_path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
 
492
  def generate(
493
  self,