patocolher commited on
Commit
a39df2c
Β·
verified Β·
1 Parent(s): 014719a

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +4 -1
  2. app.py +10 -119
Dockerfile CHANGED
@@ -71,9 +71,12 @@ RUN ffmpeg -version | head -1; \
71
  ffmpeg -encoders 2>/dev/null | grep -qE "\\s${c}\\s" && echo " βœ… $c" || echo " ⚠️ $c NΓƒO encontrado"; \
72
  done; \
73
  echo "--- decoders ---"; \
74
- for c in h264 hevc vp9 aac mp3 mpeg2video; do \
75
  ffmpeg -decoders 2>/dev/null | grep -qE "\\s${c}\\s" && echo " βœ… $c" || echo " ⚠️ $c NΓƒO encontrado"; \
76
  done; \
 
 
 
77
  echo "--- filtros VOB ---"; \
78
  for f in bwdif scale fps mpdecimate loudnorm overlay; do \
79
  ffmpeg -filters 2>/dev/null | grep -qE "\\s${f}\\s" && echo " βœ… $f" || echo " ⚠️ $f NΓƒO encontrado"; \
 
71
  ffmpeg -encoders 2>/dev/null | grep -qE "\\s${c}\\s" && echo " βœ… $c" || echo " ⚠️ $c NΓƒO encontrado"; \
72
  done; \
73
  echo "--- decoders ---"; \
74
+ for c in h264 hevc vp9 aac mp3 mpeg2video mpeg2_cuvid h264_cuvid hevc_cuvid; do \
75
  ffmpeg -decoders 2>/dev/null | grep -qE "\\s${c}\\s" && echo " βœ… $c" || echo " ⚠️ $c NΓƒO encontrado"; \
76
  done; \
77
+ echo "--- hwaccels ---"; \
78
+ ffmpeg -hwaccels 2>/dev/null | grep -qE "cuda" && echo " βœ… cuda hwaccel" || echo " ⚠️ cuda hwaccel NΓƒO encontrado"; \
79
+ ffmpeg -hwaccels 2>/dev/null | grep -qE "mpeg2_nvdec" && echo " βœ… mpeg2_nvdec" || echo " ⚠️ mpeg2_nvdec NΓƒO encontrado"; \
80
  echo "--- filtros VOB ---"; \
81
  for f in bwdif scale fps mpdecimate loudnorm overlay; do \
82
  ffmpeg -filters 2>/dev/null | grep -qE "\\s${f}\\s" && echo " βœ… $f" || echo " ⚠️ $f NΓƒO encontrado"; \
app.py CHANGED
@@ -12,19 +12,8 @@ from PIL import Image, ImageDraw
12
  # ══════════════════════════════════════════════════════════════════
13
 
14
  def gpu_disponivel():
15
- """Verifica se NVENC realmente funciona β€” nΓ£o confia sΓ³ no nvidia-smi."""
16
- # 1) nvidia-smi precisa existir e rodar
17
  r = subprocess.run(["nvidia-smi"], capture_output=True, text=True)
18
- if r.returncode != 0:
19
- return False
20
- # 2) Testa se h264_nvenc consegue abrir sessΓ£o de encoding
21
- # Faz um encode de 1 frame de cor sΓ³lida β€” se falhar, NVENC nΓ£o funciona.
22
- r = subprocess.run([
23
- "ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
24
- "-f", "lavfi", "-i", "color=c=black:s=64x64:d=0.04",
25
- "-c:v", "h264_nvenc", "-frames:v", "1",
26
- "-f", "null", "-"
27
- ], capture_output=True, text=True)
28
  return r.returncode == 0
29
 
30
 
@@ -275,8 +264,15 @@ def reencode_video(
275
  gpu_fallback = quer_gpu and not use_gpu
276
  tem_logo = logo_file is not None
277
 
 
 
 
 
 
 
278
  full_gpu_pipeline = (
279
  use_gpu and
 
280
  not remover_duplicados and
281
  resolucao == "Original" and
282
  not tem_logo
@@ -466,113 +462,8 @@ def reencode_video(
466
 
467
  if process.returncode != 0:
468
  err = process.stderr.read()
469
-
470
- # ── Fallback automΓ‘tico GPU β†’ CPU se NVENC falhar ────────
471
- if use_gpu and ("nvenc" in err.lower() or "cuda" in err.lower()
472
- or "OpenEncodeSessionEx" in err
473
- or "no capable devices" in err.lower()):
474
- yield None, (
475
- "⚠️ NVENC falhou β€” repetindo com CPU...\n"
476
- f"(motivo: {err[-200:]})"
477
- )
478
- use_gpu = False
479
- gpu_fallback = True
480
- full_gpu_pipeline = False
481
-
482
- # ReconstrΓ³i o comando sem GPU
483
- cmd_fallback = ["ffmpeg", "-hide_banner", "-loglevel", "error",
484
- "-progress", "pipe:1", "-y"]
485
- if precisa_probe_extra:
486
- cmd_fallback += ["-analyzeduration", "100M", "-probesize", "100M",
487
- "-fflags", "+genpts+discardcorrupt"]
488
- cmd_fallback += ["-i", input_path]
489
- if tem_logo:
490
- cmd_fallback += ["-i", logo_tmp]
491
-
492
- # Filtros (sempre CPU agora)
493
- vf_fb = list(vf_parts) # jΓ‘ inclui bwdif para VOB, fps, etc.
494
- if tem_logo:
495
- overlay_pos = calcular_posicao_logo(
496
- logo_posicao, logo_margem, logo_offset_x, logo_offset_y)
497
- if vf_fb:
498
- fc = (
499
- f"[0:v]{','.join(vf_fb)}[base];"
500
- f"[1:v]scale={logo_width_px}:-1[logo];"
501
- f"[base][logo]overlay={overlay_pos}:format=auto[vout]"
502
- )
503
- else:
504
- fc = (
505
- f"[1:v]scale={logo_width_px}:-1[logo];"
506
- f"[0:v][logo]overlay={overlay_pos}:format=auto[vout]"
507
- )
508
- cmd_fallback += ["-filter_complex", fc, "-map", "[vout]"]
509
- if has_audio:
510
- cmd_fallback += ["-map", "0:a"]
511
- else:
512
- if vf_fb:
513
- cmd_fallback += ["-vf", ",".join(vf_fb)]
514
-
515
- if remover_duplicados and not tem_logo:
516
- cmd_fallback += ["-fps_mode", "vfr"]
517
-
518
- # Codec de vΓ­deo CPU
519
- if "x264" in modo:
520
- cmd_fallback += ["-c:v", "libx264", "-profile:v", "high",
521
- "-preset", "slow", "-crf", str(crf_valor),
522
- "-pix_fmt", "yuv420p"]
523
- else:
524
- cmd_fallback += ["-c:v", "libx265", "-preset", "slow",
525
- "-crf", str(crf_valor), "-pix_fmt", "yuv420p",
526
- "-x265-params",
527
- "sao=0:rd=6:psy-rd=1.0:psy-rdoq=2.0:rskip=1"]
528
-
529
- # Áudio (reaproveita o que jÑ foi calculado)
530
- if has_audio:
531
- if normalizar_audio and af:
532
- cmd_fallback += ["-af", af]
533
- cmd_fallback += montar_args_audio(
534
- audio_codec_label, audio_bitrate, audio_sample_rate, int(audio_canais))
535
- else:
536
- cmd_fallback += ["-an"]
537
-
538
- cmd_fallback += ["-movflags", "+faststart"]
539
- if has_audio:
540
- cmd_fallback += [
541
- "-metadata:s:a:0", "language=por",
542
- "-metadata:s:a:0", "comment=Re-encoded by Super Re-Encoder",
543
- ]
544
- cmd_fallback.append(output_path)
545
-
546
- yield None, "⏳ Codificando com CPU (fallback)..."
547
- process2 = subprocess.Popen(
548
- cmd_fallback, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
549
- current_sec = 0.0
550
- while True:
551
- line = process2.stdout.readline()
552
- if not line and process2.poll() is not None:
553
- break
554
- if line:
555
- line = line.strip()
556
- if line.startswith("out_time_ms="):
557
- val = line.split('=')[1]
558
- if val != 'N/A':
559
- current_sec = int(val) / 1000000
560
- if total_duration > 0:
561
- pct = min(100, int(current_sec / total_duration * 100))
562
- yield None, (
563
- f"⏳ CPU fallback... {pct}% "
564
- f"({current_sec:.1f}s de {total_duration:.1f}s)"
565
- )
566
- else:
567
- yield None, f"⏳ CPU fallback... {current_sec:.1f}s processados"
568
-
569
- if process2.returncode != 0:
570
- err2 = process2.stderr.read()
571
- yield None, f"❌ Erro no FFmpeg (CPU fallback):\n{err2[-1500:]}"
572
- return
573
- else:
574
- yield None, f"❌ Erro no FFmpeg:\n{err[-1500:]}"
575
- return
576
 
577
  # ── RelatΓ³rio final ─────────────────────────────────────────
578
  orig_mb = os.path.getsize(input_path) / (1024 * 1024)
 
12
  # ══════════════════════════════════════════════════════════════════
13
 
14
  def gpu_disponivel():
15
+ """Verifica se a GPU NVIDIA estΓ‘ acessΓ­vel via nvidia-smi."""
 
16
  r = subprocess.run(["nvidia-smi"], capture_output=True, text=True)
 
 
 
 
 
 
 
 
 
 
17
  return r.returncode == 0
18
 
19
 
 
264
  gpu_fallback = quer_gpu and not use_gpu
265
  tem_logo = logo_file is not None
266
 
267
+ # VOB / MPG sΓ£o entrelaΓ§ados e exigem bwdif (filtro CPU).
268
+ # full_gpu_pipeline (= decode+encode na VRAM) Γ© incompatΓ­vel com filtros
269
+ # CPU porque exigiria transferΓͺncia GPUβ†’CPUβ†’GPU. Para esses formatos,
270
+ # o melhor Γ© decode CPU + bwdif CPU + encode NVENC na GPU.
271
+ formato_sem_full_gpu = ext in {".vob", ".mpg", ".mpeg"}
272
+
273
  full_gpu_pipeline = (
274
  use_gpu and
275
+ not formato_sem_full_gpu and
276
  not remover_duplicados and
277
  resolucao == "Original" and
278
  not tem_logo
 
462
 
463
  if process.returncode != 0:
464
  err = process.stderr.read()
465
+ yield None, f"❌ Erro no FFmpeg:\n{err[-1500:]}"
466
+ return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
 
468
  # ── RelatΓ³rio final ─────────────────────────────────────────
469
  orig_mb = os.path.getsize(input_path) / (1024 * 1024)