gnosticdev commited on
Commit
59f0ed1
verified
1 Parent(s): 2da8de0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -6
app.py CHANGED
@@ -59,6 +59,8 @@ def validar_video(video_path):
59
  # Validar que es un video
60
  clip = VideoFileClip(video_path)
61
  duracion = clip.duration
 
 
62
  clip.close()
63
 
64
  return True
@@ -66,18 +68,37 @@ def validar_video(video_path):
66
  logging.error(f"El video no es v谩lido: {e}")
67
  return False
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  def convertir_video(video_path):
70
  try:
 
 
 
 
71
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_converted:
72
  output_path = tmp_converted.name
73
 
74
- # Convertir a un formato m谩s eficiente pero manteniendo la resoluci贸n original
75
- os.system(f'ffmpeg -i "{video_path}" -c:v libx264 -crf 28 -preset ultrafast -c:a aac -b:a 96k "{output_path}" -y')
76
 
77
  # Comprobar si ahora cumple las limitaciones de tama帽o
78
  if not validar_video(output_path):
79
  # Si sigue sin cumplir, aumentar la compresi贸n pero sin cambiar la resoluci贸n
80
- os.system(f'ffmpeg -i "{output_path}" -c:v libx264 -crf 32 -preset ultrafast -c:a aac -b:a 64k "{output_path}.tmp" -y')
81
  os.remove(output_path)
82
  os.rename(f"{output_path}.tmp", output_path)
83
 
@@ -155,6 +176,11 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
155
  logging.info("Iniciando procesamiento")
156
  progress(0, desc="Validando video")
157
 
 
 
 
 
 
158
  if not validar_video(video_input):
159
  progress(0.05, desc="Optimizando formato de video")
160
  video_input = convertir_video(video_input)
@@ -197,6 +223,11 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
197
  # Cargar solo la porci贸n del video que necesitamos
198
  chunk_video = VideoFileClip(video_input).subclip(chunk_start, chunk_end)
199
 
 
 
 
 
 
200
  # Extraer la porci贸n de audio correspondiente a este bloque
201
  tts_chunk_end = min(chunk_end, tts_audio.duration)
202
  chunk_tts = None
@@ -252,6 +283,7 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
252
  audio_codec="aac",
253
  preset="ultrafast",
254
  bitrate="1M",
 
255
  ffmpeg_params=["-crf", "28"],
256
  verbose=False
257
  )
@@ -268,13 +300,20 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
268
 
269
  # A帽adir intro y outro - conservar resoluci贸n original para consistencia
270
  progress(0.85, desc="Preparando intro y outro")
 
 
271
  intro = VideoFileClip(INTRO_VIDEO)
 
 
 
 
272
  with tempfile.NamedTemporaryFile(delete=False, suffix="_intro.mp4") as tmp_intro:
273
  intro.write_videofile(
274
  tmp_intro.name,
275
  codec="libx264",
276
  audio_codec="aac",
277
- preset="ultrafast",
 
278
  bitrate="1M",
279
  ffmpeg_params=["-crf", "28"],
280
  verbose=False
@@ -282,13 +321,19 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
282
  segmentos_temp.insert(0, tmp_intro.name) # Intro al principio
283
  intro.close()
284
 
 
285
  outro = VideoFileClip(OUTRO_VIDEO)
 
 
 
 
286
  with tempfile.NamedTemporaryFile(delete=False, suffix="_outro.mp4") as tmp_outro:
287
  outro.write_videofile(
288
  tmp_outro.name,
289
  codec="libx264",
290
  audio_codec="aac",
291
  preset="ultrafast",
 
292
  bitrate="1M",
293
  ffmpeg_params=["-crf", "28"],
294
  verbose=False
@@ -298,15 +343,21 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
298
 
299
  # Unir todos los segmentos con ffmpeg
300
  progress(0.9, desc="Generando video final")
 
 
301
  with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as concat_file:
302
  # Escribir archivo de lista para concatenaci贸n
303
  for segment in segmentos_temp:
304
  concat_file.write(f"file '{segment}'\n".encode())
305
  concat_path = concat_file.name
306
-
 
307
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp_final:
308
  output_path = tmp_final.name
309
- os.system(f'ffmpeg -f concat -safe 0 -i "{concat_path}" -c copy "{output_path}" -y')
 
 
 
310
 
311
  # Limpiar archivos temporales
312
  os.remove(concat_path)
@@ -314,6 +365,13 @@ async def procesar_video(video_input, texto_tts, voz_seleccionada, progress=gr.P
314
  if os.path.exists(segment):
315
  os.remove(segment)
316
 
 
 
 
 
 
 
 
317
  eliminar_archivo_tiempo(output_path, 3600) # Eliminaci贸n despu茅s de 1 hora
318
  progress(1.0, desc="隆Video listo!")
319
  logging.info(f"Video final guardado: {output_path}")
@@ -424,6 +482,7 @@ with gr.Blocks() as demo:
424
  - Procesamiento por bloques para videos largos
425
  - M谩ximo tama帽o de archivo: 200MB
426
  - Mantiene la resoluci贸n original del video
 
427
  - Texto TTS limitado a 1000 caracteres
428
  - Las transiciones ocurren cada 30 segundos
429
  - El video contiene intro y outro predefinidos
 
59
  # Validar que es un video
60
  clip = VideoFileClip(video_path)
61
  duracion = clip.duration
62
+ fps = clip.fps
63
+ logging.info(f"Video validado: duraci贸n={duracion}s, fps={fps}")
64
  clip.close()
65
 
66
  return True
 
68
  logging.error(f"El video no es v谩lido: {e}")
69
  return False
70
 
71
+ def obtener_info_video(video_path):
72
+ """Obtiene informaci贸n b谩sica del video como FPS, duraci贸n y tama帽o"""
73
+ try:
74
+ clip = VideoFileClip(video_path)
75
+ info = {
76
+ "fps": clip.fps,
77
+ "duration": clip.duration,
78
+ "size": clip.size
79
+ }
80
+ clip.close()
81
+ return info
82
+ except Exception as e:
83
+ logging.error(f"Error al obtener info del video: {e}")
84
+ return {"fps": 30, "duration": 0, "size": (640, 360)} # valores por defecto
85
+
86
  def convertir_video(video_path):
87
  try:
88
+ # Obtener FPS del video original para mantenerlo
89
+ info = obtener_info_video(video_path)
90
+ fps = info["fps"] if info["fps"] else 30 # Valor por defecto si no se puede determinar
91
+
92
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_converted:
93
  output_path = tmp_converted.name
94
 
95
+ # Convertir a un formato m谩s eficiente pero manteniendo la resoluci贸n original Y el framerate
96
+ os.system(f'ffmpeg -i "{video_path}" -c:v libx264 -crf 28 -preset ultrafast -r {fps} -c:a aac -b:a 96k "{output_path}" -y')
97
 
98
  # Comprobar si ahora cumple las limitaciones de tama帽o
99
  if not validar_video(output_path):
100
  # Si sigue sin cumplir, aumentar la compresi贸n pero sin cambiar la resoluci贸n
101
+ os.system(f'ffmpeg -i "{output_path}" -c:v libx264 -crf 32 -preset ultrafast -r {fps} -c:a aac -b:a 64k "{output_path}.tmp" -y')
102
  os.remove(output_path)
103
  os.rename(f"{output_path}.tmp", output_path)
104
 
 
176
  logging.info("Iniciando procesamiento")
177
  progress(0, desc="Validando video")
178
 
179
+ # Obtener informaci贸n del video original
180
+ original_info = obtener_info_video(video_input)
181
+ original_fps = original_info["fps"]
182
+ logging.info(f"Video original - FPS: {original_fps}, Tama帽o: {original_info['size']}")
183
+
184
  if not validar_video(video_input):
185
  progress(0.05, desc="Optimizando formato de video")
186
  video_input = convertir_video(video_input)
 
223
  # Cargar solo la porci贸n del video que necesitamos
224
  chunk_video = VideoFileClip(video_input).subclip(chunk_start, chunk_end)
225
 
226
+ # Aseguramos que el framerate se mantiene en todos los clips
227
+ if original_fps and chunk_video.fps != original_fps:
228
+ logging.info(f"Ajustando FPS del chunk {chunk_idx+1} a {original_fps}")
229
+ chunk_video = chunk_video.set_fps(original_fps)
230
+
231
  # Extraer la porci贸n de audio correspondiente a este bloque
232
  tts_chunk_end = min(chunk_end, tts_audio.duration)
233
  chunk_tts = None
 
283
  audio_codec="aac",
284
  preset="ultrafast",
285
  bitrate="1M",
286
+ fps=original_fps, # Asegurar que se mantiene el FPS original
287
  ffmpeg_params=["-crf", "28"],
288
  verbose=False
289
  )
 
300
 
301
  # A帽adir intro y outro - conservar resoluci贸n original para consistencia
302
  progress(0.85, desc="Preparando intro y outro")
303
+
304
+ # Procesamiento del intro
305
  intro = VideoFileClip(INTRO_VIDEO)
306
+ # Asegurar que se utiliza el mismo FPS que el video original
307
+ if original_fps and intro.fps != original_fps:
308
+ intro = intro.set_fps(original_fps)
309
+
310
  with tempfile.NamedTemporaryFile(delete=False, suffix="_intro.mp4") as tmp_intro:
311
  intro.write_videofile(
312
  tmp_intro.name,
313
  codec="libx264",
314
  audio_codec="aac",
315
+ preset="ultrafast",
316
+ fps=original_fps, # Usar FPS original
317
  bitrate="1M",
318
  ffmpeg_params=["-crf", "28"],
319
  verbose=False
 
321
  segmentos_temp.insert(0, tmp_intro.name) # Intro al principio
322
  intro.close()
323
 
324
+ # Procesamiento del outro
325
  outro = VideoFileClip(OUTRO_VIDEO)
326
+ # Asegurar que se utiliza el mismo FPS que el video original
327
+ if original_fps and outro.fps != original_fps:
328
+ outro = outro.set_fps(original_fps)
329
+
330
  with tempfile.NamedTemporaryFile(delete=False, suffix="_outro.mp4") as tmp_outro:
331
  outro.write_videofile(
332
  tmp_outro.name,
333
  codec="libx264",
334
  audio_codec="aac",
335
  preset="ultrafast",
336
+ fps=original_fps, # Usar FPS original
337
  bitrate="1M",
338
  ffmpeg_params=["-crf", "28"],
339
  verbose=False
 
343
 
344
  # Unir todos los segmentos con ffmpeg
345
  progress(0.9, desc="Generando video final")
346
+
347
+ # Crear un archivo de metadatos para ffmpeg
348
  with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as concat_file:
349
  # Escribir archivo de lista para concatenaci贸n
350
  for segment in segmentos_temp:
351
  concat_file.write(f"file '{segment}'\n".encode())
352
  concat_path = concat_file.name
353
+
354
+ # Usar FFmpeg para concatenar todos los segmentos
355
  with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp_final:
356
  output_path = tmp_final.name
357
+ # Usar el par谩metro -vsync para asegurar que se mantiene la sincronizaci贸n de video
358
+ cmd = f'ffmpeg -f concat -safe 0 -i "{concat_path}" -vsync cfr -c copy "{output_path}" -y'
359
+ logging.info(f"Ejecutando comando FFmpeg: {cmd}")
360
+ os.system(cmd)
361
 
362
  # Limpiar archivos temporales
363
  os.remove(concat_path)
 
365
  if os.path.exists(segment):
366
  os.remove(segment)
367
 
368
+ # Verificar que el video final tiene la duraci贸n esperada
369
+ try:
370
+ final_info = obtener_info_video(output_path)
371
+ logging.info(f"Video final - Duraci贸n: {final_info['duration']}s, FPS: {final_info['fps']}")
372
+ except Exception as e:
373
+ logging.error(f"No se pudo verificar el video final: {e}")
374
+
375
  eliminar_archivo_tiempo(output_path, 3600) # Eliminaci贸n despu茅s de 1 hora
376
  progress(1.0, desc="隆Video listo!")
377
  logging.info(f"Video final guardado: {output_path}")
 
482
  - Procesamiento por bloques para videos largos
483
  - M谩ximo tama帽o de archivo: 200MB
484
  - Mantiene la resoluci贸n original del video
485
+ - Mantiene la velocidad original del video (FPS)
486
  - Texto TTS limitado a 1000 caracteres
487
  - Las transiciones ocurren cada 30 segundos
488
  - El video contiene intro y outro predefinidos