diff --git a/loop.py b/loop.py index 9867212..813c899 100644 --- a/loop.py +++ b/loop.py @@ -99,38 +99,33 @@ class AutoLoopCalculatorLTX: potential_effective_frames = source_frame_count // select_every_nth - # Truncar al (8n + 1) más cercano hacia ARRIBA (Acolchado) if potential_effective_frames < 9: - safe_effective_frames = 9 # Too short, bypass + safe_effective_frames = 9 else: safe_effective_frames = ((potential_effective_frames + 6) // 8) * 8 + 1 - safe_source_frame_count = safe_effective_frames * select_every_nth - loop.global_source_frame_count = safe_source_frame_count + # 🚀 FIX: Conservamos el límite FÍSICO real del vídeo para el timeline global + physical_source_frame_count = potential_effective_frames * select_every_nth + loop.global_source_frame_count = physical_source_frame_count effective_padding = safe_effective_frames - potential_effective_frames - # Ajuste proporcional forzando regla 8n + 1 + # Ajuste proporcional estimated_loops = math.ceil(safe_effective_frames / target_frames_per_loop) if estimated_loops > 0: optimal_target = math.ceil(safe_effective_frames / estimated_loops) - # Encontrar el 8n + 1 más cercano hacia arriba para cubrir el total adjusted_target = ((optimal_target - 1 + 7) // 8) * 8 + 1 target_frames_per_loop = adjusted_target print(f" -> ⚖️ Ajuste Proporcional LTX: Target recalculado a {adjusted_target} frames por ciclo.") - # --- LOGS MEJORADOS Y TRANSPARENTES --- print(f" -> 🎞️ Capacidad del video original: {potential_effective_frames} frames (Nth: {select_every_nth})") if effective_padding > 0: print(f" -> 🛡️ Ajuste VAE: Se pedirán {safe_effective_frames} frames (Acolchado técnico: Se rellenarán {effective_padding} frames)") else: print(f" -> ✅ Ajuste VAE: Perfecto. Regla 8n+1 detectada.") - print(f" -> 📊 Timeline final: 0 a {safe_source_frame_count} (de {source_frame_count} totales)") - # ------------------------------------------------------------- + print(f" -> 📊 Timeline final: 0 a {physical_source_frame_count} (Límite Físico Real)") loop.global_select_every_nth = select_every_nth - - # Indicador global para el Stitcher y Sender (LTX mode activo) global global_ltx_mode global_ltx_mode = True @@ -138,19 +133,18 @@ class AutoLoopCalculatorLTX: print(f"\n{'='*50}") print(f"📊 [DEBUG] NODO: Auto Loop Calculator (LTX 2.3)") - print(f" -> Timeline seguro ajustado a LTX: {current_pos} / {safe_source_frame_count} (Original: {source_frame_count})") + print(f" -> Timeline físico ajustado a LTX: {current_pos} / {physical_source_frame_count} (Original: {source_frame_count})") - if current_pos >= safe_source_frame_count: + if current_pos >= physical_source_frame_count: return (1, current_pos, select_every_nth) - frames_left = safe_source_frame_count - current_pos + frames_left = physical_source_frame_count - current_pos equitable_target = target_frames_per_loop * select_every_nth - ideal_cut = current_pos + equitable_target if frames_left <= equitable_target: - best_cut = safe_source_frame_count + best_cut = physical_source_frame_count print(f" -> 🧮 Absorbiendo resto final: meta fijada en frame {best_cut}") else: best_cut = ideal_cut @@ -159,18 +153,15 @@ class AutoLoopCalculatorLTX: best_cut = closest_face print(f" -> ✂️ Corte Inteligente proyectado: {best_cut} (Meta equitativa: {ideal_cut})") else: - print(f" -> ⚖️ Sin caras detectadas. Forzando corte equitativo: {ideal_cut}") + print(f" -> ⚖️ Sin caras. Forzando corte equitativo: {ideal_cut}") effective_chunk_frames = math.ceil((best_cut - current_pos) / select_every_nth) - - # Redondear siempre hacia ARRIBA al (8n + 1) más cercano effective_chunk_frames = ((effective_chunk_frames + 6) // 8) * 8 + 1 if effective_chunk_frames < 9: - effective_chunk_frames = 9 # Mínimo vital LTX + effective_chunk_frames = 9 - # ELIMINAMOS el recorte final que rompe la regla 8n + 1 - if current_pos + (effective_chunk_frames * select_every_nth) >= safe_source_frame_count: + if current_pos + (effective_chunk_frames * select_every_nth) >= physical_source_frame_count: print(f" -> 🏁 Chunk final LTX detectado. Ajustando a {effective_chunk_frames} frames para mantener regla 8n+1.") skip_frames = current_pos diff --git a/video.py b/video.py index 67139d5..53fa7fb 100644 --- a/video.py +++ b/video.py @@ -404,8 +404,9 @@ class AutoLoopCalculatorWan: potential_effective_frames = source_frame_count // select_every_nth safe_effective_frames = ((potential_effective_frames + 3) // 4) * 4 - safe_source_frame_count = safe_effective_frames * select_every_nth - loop.global_source_frame_count = safe_source_frame_count + # 🚀 FIX: Conservamos el límite FÍSICO real del vídeo para el timeline global + physical_source_frame_count = potential_effective_frames * select_every_nth + loop.global_source_frame_count = physical_source_frame_count effective_padding = safe_effective_frames - potential_effective_frames loop.global_select_every_nth = select_every_nth @@ -413,50 +414,42 @@ class AutoLoopCalculatorWan: # 2. Ajuste Proporcional Real (Evitar micro-ciclos al final) estimated_loops = math.ceil(safe_effective_frames / target_frames_per_loop) if estimated_loops > 0: - # Repartir los frames equitativamente optimal_target = math.ceil(safe_effective_frames / estimated_loops) - # Asegurar que el nuevo target sea múltiplo de 4 (redondeando hacia arriba por seguridad) adjusted_target = ((optimal_target + 3) // 4) * 4 - print(f" -> ⚖️ Ajuste Proporcional: Target recalculado de {target_frames_per_loop} a {adjusted_target} frames por ciclo (para {estimated_loops} ciclos)") target_frames_per_loop = adjusted_target - # --- LOGS MEJORADOS Y TRANSPARENTES --- print(f" -> 🎞️ Capacidad del video original: {potential_effective_frames} frames (Nth: {select_every_nth})") if effective_padding > 0: print(f" -> 🛡️ Ajuste VAE: Se pedirán {safe_effective_frames} frames (Acolchado técnico: Se rellenarán {effective_padding} frames)") else: print(f" -> ✅ Ajuste VAE: Perfecto. Múltiplo de 4 detectado.") - print(f" -> 📊 Timeline final: 0 a {safe_source_frame_count} (de {source_frame_count} totales)") - # ------------------------------------------------------------- + print(f" -> 📊 Timeline final: 0 a {physical_source_frame_count} (Límite Físico Real)") current_pos = getattr(loop, 'global_accumulated_frames', 0) print(f"\n{'='*50}") print(f"📊 [DEBUG] NODO: Auto Loop Calculator (WanVideo 3D VAE)") - print(f" -> Timeline seguro ajustado a múltiplos de 4: {current_pos} / {safe_source_frame_count} (Original: {source_frame_count})") + print(f" -> Timeline físico ajustado: {current_pos} / {physical_source_frame_count} (Original: {source_frame_count})") - # Prevención de desbordamiento de bucle - if current_pos >= safe_source_frame_count: + # Prevención de desbordamiento de bucle (Usando límite físico) + if current_pos >= physical_source_frame_count: return (4, current_pos, select_every_nth) - frames_left = safe_source_frame_count - current_pos + frames_left = physical_source_frame_count - current_pos equitable_target = target_frames_per_loop * select_every_nth - ideal_cut = current_pos + equitable_target if frames_left <= equitable_target: - best_cut = safe_source_frame_count + best_cut = physical_source_frame_count print(f" -> 🧮 Absorbiendo resto final seguro: meta fijada en frame {best_cut}") else: best_cut = ideal_cut if safe_faces_list and len(safe_faces_list) > 0: closest_face = min(safe_faces_list, key=lambda x: abs(x - ideal_cut)) - # Distancia al corte de cara chunk_from_face = math.ceil((closest_face - current_pos) / select_every_nth) - # Blindaje matemático x4 para el corte de cara safe_chunk_from_face = (chunk_from_face // 4) * 4 if safe_chunk_from_face < 4: safe_chunk_from_face = 4 @@ -465,19 +458,14 @@ class AutoLoopCalculatorWan: else: print(f" -> ⚖️ Sin caras. Forzando corte equitativo x4: {ideal_cut}") - # 4. Cálculo final del chunk consolidado effective_chunk_frames = math.ceil((best_cut - current_pos) / select_every_nth) - - # Redondear siempre hacia ARRIBA al múltiplo de 4 más cercano para evitar chunks inválidos effective_chunk_frames = ((effective_chunk_frames + 3) // 4) * 4 if effective_chunk_frames < 4: effective_chunk_frames = 4 - # ELIMINAMOS el recorte final que rompe el múltiplo de 4. - # Si pedimos más frames de los que quedan, VHS duplicará el último frame automáticamente, - # salvando así el renderizado sin crashear el 3D VAE. - if current_pos + (effective_chunk_frames * select_every_nth) >= safe_source_frame_count: + # Comprobación contra el límite físico para evitar pedir más allá del final + if current_pos + (effective_chunk_frames * select_every_nth) >= physical_source_frame_count: print(f" -> 🏁 Chunk final detectado. Ajustando a {effective_chunk_frames} frames para mantener múltiplo de 4.") skip_frames = current_pos