patocolher commited on
Commit
2a0aec1
·
verified ·
1 Parent(s): 8ee57d9

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +24 -0
  2. app.py +112 -0
  3. readme.md +10 -0
  4. requirements.txt +1 -0
Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ # Instala ferramentas básicas
4
+ RUN apt-get update && apt-get install -y --no-install-recommends \
5
+ wget xz-utils ca-certificates \
6
+ && rm -rf /var/lib/apt/lists/*
7
+
8
+ # Baixa e instala FFmpeg mais recente com suporte completo:
9
+ # - h264_nvenc + hevc_nvenc (GPU T4)
10
+ # - libx264 + libx265 (CPU)
11
+ # - libfdk_aac
12
+ RUN wget -q https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz -O ffmpeg.tar.xz \
13
+ && tar -xJf ffmpeg.tar.xz --strip-components=1 -C /usr/local/bin --wildcards '*/ffmpeg' '*/ffprobe' \
14
+ && rm ffmpeg.tar.xz \
15
+ && ffmpeg -version | head -5 \
16
+ && ffmpeg -encoders | grep -E 'nvenc|libx264|libx265|libfdk_aac' || echo "FFmpeg pronto"
17
+
18
+ WORKDIR /app
19
+ COPY app.py .
20
+
21
+ RUN pip install --no-cache-dir gradio
22
+
23
+ EXPOSE 7860
24
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import os
4
+ import json
5
+ import tempfile
6
+
7
+ def reencode_video(video_file, modo, resolucao):
8
+ if video_file is None:
9
+ return None, "❌ Nenhum vídeo enviado!"
10
+
11
+ # Salva o vídeo enviado
12
+ input_path = "input.mp4"
13
+ with open(input_path, "wb") as f:
14
+ f.write(video_file)
15
+
16
+ output_path = "output_reencoded.mp4"
17
+ stats_path = "loudnorm_stats.json"
18
+
19
+ # PASSO 1: Análise loudnorm EBU R128 (exatamente como você pediu)
20
+ subprocess.run([
21
+ "ffmpeg", "-hide_banner", "-loglevel", "error", "-y",
22
+ "-i", input_path, "-af", "loudnorm=print_format=json",
23
+ "-f", "null", "-"
24
+ ], stderr=open(stats_path, "w"))
25
+
26
+ # Lê os valores measured
27
+ with open(stats_path, "r") as f:
28
+ stats = json.load(f)
29
+ m_I = stats["input_i"]
30
+ m_TP = stats["input_tp"]
31
+ m_LRA = stats["input_lra"]
32
+ m_thresh = stats["input_thresh"]
33
+ offset = stats["target_offset"]
34
+
35
+ # Filtro de vídeo (mpdecimate + resolução)
36
+ if resolucao == "Original":
37
+ vf = "mpdecimate=hi=1"
38
+ else:
39
+ w, h = resolucao.split("x")
40
+ vf = f"scale={w}:{h}:force_original_aspect_ratio=decrease,pad={w}:{h}:(ow-iw)/2:(oh-ih)/2,mpdecimate=hi=1"
41
+
42
+ # Comando base (com -hwaccel cuda quando for GPU)
43
+ cmd = ["ffmpeg", "-hide_banner", "-loglevel", "error", "-stats", "-y"]
44
+ if "GPU" in modo:
45
+ cmd += ["-hwaccel", "cuda", "-hwaccel_output_format", "cuda"]
46
+ cmd += ["-i", input_path, "-vf", vf, "-vsync", "vfr", "-r", "24"]
47
+
48
+ # Codec de vídeo (exatamente os 4 comandos que você pediu)
49
+ if "x264" in modo:
50
+ if "GPU" in modo:
51
+ cmd += ["-c:v", "h264_nvenc", "-preset", "p7", "-tune", "hq", "-rc", "vbr", "-cq", "24", "-b:v", "0", "-profile:v", "high", "-pix_fmt", "yuv420p"]
52
+ else:
53
+ cmd += ["-c:v", "libx264", "-profile:v", "high", "-preset", "slow", "-crf", "24", "-pix_fmt", "yuv420p"]
54
+ else: # x265
55
+ if "GPU" in modo:
56
+ cmd += ["-c:v", "hevc_nvenc", "-preset", "p7", "-tune", "uhq", "-rc", "vbr", "-cq", "24", "-b:v", "0", "-profile:v", "main", "-pix_fmt", "yuv420p"]
57
+ else:
58
+ cmd += ["-c:v", "libx265", "-preset", "slow", "-crf", "24", "-pix_fmt", "yuv420p", "-x265-params", "sao=0:rd=6:psy-rd=1.0:psy-rdoq=2.0:rskip=1"]
59
+
60
+ # Áudio + loudnorm + metadata (igual para todos)
61
+ cmd += [
62
+ "-c:a", "libfdk_aac", "-profile:a", "aac_he_v2", "-b:a", "32k", "-ar", "22050", "-ac", "2",
63
+ "-af", f"loudnorm=I=-23:TP=-2:LRA=7:linear=true:measured_I={m_I}:measured_tp={m_TP}:measured_LRA={m_LRA}:measured_thresh={m_thresh}:offset={offset}",
64
+ "-movflags", "+faststart",
65
+ "-metadata:s:a:0", "language=por",
66
+ "-metadata:s:a:0", "comment=Re-encoded by Super Re-Encoder - https://t.me/virumaniaa",
67
+ output_path
68
+ ]
69
+
70
+ # Executa
71
+ result = subprocess.run(cmd, capture_output=True, text=True)
72
+ if result.returncode != 0:
73
+ return None, f"❌ Erro no FFmpeg:\n{result.stderr[-800:]}"
74
+
75
+ # Relatório de redução
76
+ orig_mb = os.path.getsize(input_path) / (1024*1024)
77
+ final_mb = os.path.getsize(output_path) / (1024*1024)
78
+ reducao = round((1 - final_mb / orig_mb) * 100, 1)
79
+
80
+ return output_path, f"✅ Concluído!\nOriginal: {orig_mb:.1f} MB\nFinal: {final_mb:.1f} MB\nRedução: {reducao}%"
81
+
82
+ # Interface 100% em PT-BR
83
+ with gr.Blocks(title="Super Re-Encoder", theme=gr.themes.Soft()) as demo:
84
+ gr.Markdown("# 🎥 **Super Re-Encoder**\nSuba qualquer vídeo e baixe com **tamanho bem menor** e qualidade praticamente igual.")
85
+ gr.Markdown("**4 modos** • **Resoluções** • **CRF 24 + mpdecimate + loudnorm**")
86
+
87
+ with gr.Row():
88
+ video = gr.Video(label="📤 Seu vídeo", sources=["upload"], height=300)
89
+
90
+ with gr.Column():
91
+ modo = gr.Radio(
92
+ choices=["x264 GPU (máx T4)", "x265 GPU (máx T4)", "x264 CPU only", "x265 CPU only"],
93
+ value="x264 GPU (máx T4)",
94
+ label="🔥 Modo de compressão",
95
+ info="GPU = mais rápido na T4 | CPU = mais estável"
96
+ )
97
+ res = gr.Dropdown(
98
+ choices=["Original", "480p (854x480)", "720p (1280x720)", "1080p (1920x1080)"],
99
+ value="Original",
100
+ label="📐 Resolução",
101
+ info="Original mantém o tamanho do vídeo. Outras fazem up/downscale com barras pretas se necessário."
102
+ )
103
+
104
+ btn = gr.Button("🚀 RE-ENCODE AGORA", variant="primary", size="large")
105
+
106
+ out_video = gr.Video(label="📥 Vídeo final (baixe aqui)")
107
+ status = gr.Textbox(label="📋 Relatório", lines=5)
108
+
109
+ btn.click(reencode_video, inputs=[video, modo, res], outputs=[out_video, status])
110
+
111
+ demo.queue(max_size=5)
112
+ demo.launch()
readme.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Super Re-Encoder
3
+ emoji: 🎥
4
+ colorFrom: yellow
5
+ colorTo: orange
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ short_description: Re-encode vídeos com alta qualidade e tamanho mínimo
10
+ ---
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ gradio>=5.0.0