Spaces:
Paused
Paused
Upload 2 files
Browse files- Dockerfile +6 -3
- app.py +41 -18
Dockerfile
CHANGED
|
@@ -8,12 +8,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
| 8 |
libfdk-aac-dev libx264-dev libx265-dev libnuma-dev \
|
| 9 |
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
|
| 11 |
-
# nv-codec-headers (necessΓ‘rio para h264_nvenc / hevc_nvenc)
|
| 12 |
RUN git clone --depth 1 https://git.videolan.org/git/ffmpeg/nv-codec-headers.git /tmp/nv-codec-headers \
|
| 13 |
&& make -C /tmp/nv-codec-headers install \
|
| 14 |
&& rm -rf /tmp/nv-codec-headers
|
| 15 |
|
| 16 |
-
# Compila ffmpeg 7.1.1 com libfdk_aac + NVENC
|
| 17 |
RUN wget -q -O /tmp/ffmpeg.tar.bz2 https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.bz2 \
|
| 18 |
&& tar xf /tmp/ffmpeg.tar.bz2 -C /tmp \
|
| 19 |
&& rm /tmp/ffmpeg.tar.bz2 \
|
|
@@ -25,14 +25,16 @@ RUN wget -q -O /tmp/ffmpeg.tar.bz2 https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.
|
|
| 25 |
--disable-everything \
|
| 26 |
--enable-encoder=libx264,libx265,libfdk_aac,aac,h264_nvenc,hevc_nvenc \
|
| 27 |
--enable-decoder=h264,hevc,aac,mp3,ac3,eac3,opus,vorbis,flac,pcm_s16le,pcm_s16be \
|
|
|
|
| 28 |
--enable-demuxer=mov,mp4,matroska,avi,flv,mpegts,wav,mp3,aac,flac \
|
| 29 |
--enable-muxer=mp4,matroska,null \
|
| 30 |
-
--enable-filter=loudnorm,volume,aresample,scale,pad,mpdecimate,fps,null \
|
| 31 |
--enable-protocol=file,pipe \
|
| 32 |
--enable-libx264 \
|
| 33 |
--enable-libx265 \
|
| 34 |
--enable-libfdk-aac \
|
| 35 |
--enable-nvenc \
|
|
|
|
| 36 |
--enable-cuda \
|
| 37 |
--enable-cuvid \
|
| 38 |
--extra-cflags="-O2 -pipe -I/usr/local/cuda/include" \
|
|
@@ -63,6 +65,7 @@ COPY --from=builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe
|
|
| 63 |
|
| 64 |
RUN ffmpeg -version | head -3 \
|
| 65 |
&& ffmpeg -encoders 2>/dev/null | grep -E "fdk|nvenc" \
|
|
|
|
| 66 |
&& echo "β
ffmpeg OK"
|
| 67 |
|
| 68 |
WORKDIR /app
|
|
|
|
| 8 |
libfdk-aac-dev libx264-dev libx265-dev libnuma-dev \
|
| 9 |
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
|
| 11 |
+
# nv-codec-headers (necessΓ‘rio para h264_nvenc / hevc_nvenc / cuvid)
|
| 12 |
RUN git clone --depth 1 https://git.videolan.org/git/ffmpeg/nv-codec-headers.git /tmp/nv-codec-headers \
|
| 13 |
&& make -C /tmp/nv-codec-headers install \
|
| 14 |
&& rm -rf /tmp/nv-codec-headers
|
| 15 |
|
| 16 |
+
# Compila ffmpeg 7.1.1 com libfdk_aac + NVENC + scale_cuda
|
| 17 |
RUN wget -q -O /tmp/ffmpeg.tar.bz2 https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.bz2 \
|
| 18 |
&& tar xf /tmp/ffmpeg.tar.bz2 -C /tmp \
|
| 19 |
&& rm /tmp/ffmpeg.tar.bz2 \
|
|
|
|
| 25 |
--disable-everything \
|
| 26 |
--enable-encoder=libx264,libx265,libfdk_aac,aac,h264_nvenc,hevc_nvenc \
|
| 27 |
--enable-decoder=h264,hevc,aac,mp3,ac3,eac3,opus,vorbis,flac,pcm_s16le,pcm_s16be \
|
| 28 |
+
--enable-hwaccel=h264_nvdec,hevc_nvdec \
|
| 29 |
--enable-demuxer=mov,mp4,matroska,avi,flv,mpegts,wav,mp3,aac,flac \
|
| 30 |
--enable-muxer=mp4,matroska,null \
|
| 31 |
+
--enable-filter=loudnorm,volume,aresample,scale,scale_cuda,hwupload_cuda,hwdownload,pad,mpdecimate,fps,null \
|
| 32 |
--enable-protocol=file,pipe \
|
| 33 |
--enable-libx264 \
|
| 34 |
--enable-libx265 \
|
| 35 |
--enable-libfdk-aac \
|
| 36 |
--enable-nvenc \
|
| 37 |
+
--enable-nvdec \
|
| 38 |
--enable-cuda \
|
| 39 |
--enable-cuvid \
|
| 40 |
--extra-cflags="-O2 -pipe -I/usr/local/cuda/include" \
|
|
|
|
| 65 |
|
| 66 |
RUN ffmpeg -version | head -3 \
|
| 67 |
&& ffmpeg -encoders 2>/dev/null | grep -E "fdk|nvenc" \
|
| 68 |
+
&& ffmpeg -filters 2>/dev/null | grep -E "scale_cuda|hwupload" \
|
| 69 |
&& echo "β
ffmpeg OK"
|
| 70 |
|
| 71 |
WORKDIR /app
|
app.py
CHANGED
|
@@ -56,6 +56,11 @@ def reencode_video(video_file, modo, resolucao, fps, crf_valor, normalizar_audio
|
|
| 56 |
use_gpu = quer_gpu and gpu_disponivel()
|
| 57 |
gpu_fallback = quer_gpu and not use_gpu
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
# ββ Filtro de vΓdeo βββββββββββββββββββββββββββββββββββββββββ
|
| 60 |
vf_parts = []
|
| 61 |
|
|
@@ -64,26 +69,40 @@ def reencode_video(video_file, modo, resolucao, fps, crf_valor, normalizar_audio
|
|
| 64 |
tw, th = m.group(1), m.group(2)
|
| 65 |
if is_vertical:
|
| 66 |
tw, th = th, tw
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
f"
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
|
|
|
|
|
|
| 73 |
|
| 74 |
-
if
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
vf = ",".join(vf_parts) if vf_parts else
|
| 78 |
|
| 79 |
# ββ Monta comando base ββββββββββββββββββββββββββββββββββββββ
|
| 80 |
-
# NOTA: Removido o -hwaccel cuda. Como usamos filtros de software (-vf),
|
| 81 |
-
# deixar o FFmpeg decodificar na CPU e enviar direto pro NVENC Γ© muito
|
| 82 |
-
# mais rΓ‘pido do que ficar transferindo frames da GPU pra CPU e vice-versa.
|
| 83 |
cmd = ["ffmpeg", "-hide_banner", "-loglevel", "error", "-progress", "pipe:1", "-y"]
|
| 84 |
-
cmd += ["-i", input_path, "-vf", vf]
|
| 85 |
|
| 86 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
cmd += ["-fps_mode", "vfr"]
|
| 88 |
|
| 89 |
# ββ Codec de vΓdeo + CRF/CQ βββββββββββββββββββββββββββββββββ
|
|
@@ -192,12 +211,16 @@ def reencode_video(video_file, modo, resolucao, fps, crf_valor, normalizar_audio
|
|
| 192 |
reducao = round((1 - final_mb / orig_mb) * 100, 1)
|
| 193 |
|
| 194 |
extras = []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
if normalizar_audio and has_audio:
|
| 196 |
extras.append("Γ‘udio normalizado")
|
| 197 |
elif not has_audio:
|
| 198 |
extras.append("β οΈ sem faixa de Γ‘udio")
|
| 199 |
if remover_duplicados:
|
| 200 |
-
extras.append("
|
| 201 |
if gpu_fallback:
|
| 202 |
extras.append("β οΈ GPU indisponΓvel β usou CPU")
|
| 203 |
|
|
@@ -208,7 +231,7 @@ def reencode_video(video_file, modo, resolucao, fps, crf_valor, normalizar_audio
|
|
| 208 |
f"ReduΓ§Γ£o : {reducao}%\n"
|
| 209 |
f"FPS : {fps}\n"
|
| 210 |
f"CRF/CQ : {crf_valor}\n"
|
| 211 |
-
f"Codec : {'NVENC' if use_gpu else 'CPU'}\n"
|
| 212 |
f"Extras : {' | '.join(extras) if extras else 'nenhum'}"
|
| 213 |
)
|
| 214 |
|
|
@@ -256,7 +279,7 @@ with gr.Blocks(title="Super Re-Encoder") as demo:
|
|
| 256 |
normalizar_audio = gr.Checkbox(value=True,
|
| 257 |
label="π Normalizar Γ‘udio (loudnorm -23 LUFS)")
|
| 258 |
remover_duplicados = gr.Checkbox(value=True,
|
| 259 |
-
label="ποΈ Remover frames duplicados (mpdecimate)")
|
| 260 |
|
| 261 |
btn = gr.Button("π RE-ENCODE AGORA", variant="primary", size="large")
|
| 262 |
|
|
@@ -271,4 +294,4 @@ with gr.Blocks(title="Super Re-Encoder") as demo:
|
|
| 271 |
)
|
| 272 |
|
| 273 |
demo.queue(max_size=5)
|
| 274 |
-
demo.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft())
|
|
|
|
| 56 |
use_gpu = quer_gpu and gpu_disponivel()
|
| 57 |
gpu_fallback = quer_gpu and not use_gpu
|
| 58 |
|
| 59 |
+
# Pipeline 100% GPU sΓ³ Γ© possΓvel sem mpdecimate.
|
| 60 |
+
# O mpdecimate nΓ£o tem equivalente CUDA no FFmpeg, entΓ£o quando estΓ‘
|
| 61 |
+
# ativo o decode e os filtros sΓ£o forΓ§ados a rodar na CPU.
|
| 62 |
+
full_gpu_pipeline = use_gpu and not remover_duplicados
|
| 63 |
+
|
| 64 |
# ββ Filtro de vΓdeo βββββββββββββββββββββββββββββββββββββββββ
|
| 65 |
vf_parts = []
|
| 66 |
|
|
|
|
| 69 |
tw, th = m.group(1), m.group(2)
|
| 70 |
if is_vertical:
|
| 71 |
tw, th = th, tw
|
| 72 |
+
if full_gpu_pipeline:
|
| 73 |
+
# scale_cuda mantΓ©m o frame na VRAM β zero transferΓͺncia CPUβGPU
|
| 74 |
+
vf_parts.append(f"scale_cuda=w={tw}:h={th}:interp_algo=lanczos")
|
| 75 |
+
else:
|
| 76 |
+
vf_parts.append(
|
| 77 |
+
f"scale={tw}:{th}:force_original_aspect_ratio=increase,"
|
| 78 |
+
f"crop={tw}:{th}"
|
| 79 |
+
)
|
| 80 |
|
| 81 |
+
if not full_gpu_pipeline:
|
| 82 |
+
# No pipeline de CPU, fps e mpdecimate ficam no filtro de vΓdeo
|
| 83 |
+
vf_parts.append(f"fps={fps}")
|
| 84 |
+
if remover_duplicados:
|
| 85 |
+
vf_parts.append("mpdecimate=hi=1")
|
| 86 |
|
| 87 |
+
vf = ",".join(vf_parts) if vf_parts else None
|
| 88 |
|
| 89 |
# ββ Monta comando base ββββββββββββββββββββββββββββββββββββββ
|
|
|
|
|
|
|
|
|
|
| 90 |
cmd = ["ffmpeg", "-hide_banner", "-loglevel", "error", "-progress", "pipe:1", "-y"]
|
|
|
|
| 91 |
|
| 92 |
+
if full_gpu_pipeline:
|
| 93 |
+
# Decodifica direto na GPU β frames ficam na VRAM o tempo todo
|
| 94 |
+
# Fluxo: GPU decode β scale_cuda (VRAM) β NVENC encode
|
| 95 |
+
cmd += ["-hwaccel", "cuda", "-hwaccel_output_format", "cuda"]
|
| 96 |
+
|
| 97 |
+
cmd += ["-i", input_path]
|
| 98 |
+
|
| 99 |
+
if vf:
|
| 100 |
+
cmd += ["-vf", vf]
|
| 101 |
+
|
| 102 |
+
if full_gpu_pipeline:
|
| 103 |
+
# FPS definido via parΓ’metro de saΓda β sem precisar de filtro de software
|
| 104 |
+
cmd += ["-r", str(fps)]
|
| 105 |
+
elif remover_duplicados:
|
| 106 |
cmd += ["-fps_mode", "vfr"]
|
| 107 |
|
| 108 |
# ββ Codec de vΓdeo + CRF/CQ βββββββββββββββββββββββββββββββββ
|
|
|
|
| 211 |
reducao = round((1 - final_mb / orig_mb) * 100, 1)
|
| 212 |
|
| 213 |
extras = []
|
| 214 |
+
if full_gpu_pipeline:
|
| 215 |
+
extras.append("pipeline GPU completo (decode+scale+encode na VRAM)")
|
| 216 |
+
elif use_gpu:
|
| 217 |
+
extras.append("encode NVENC / decode+scale na CPU")
|
| 218 |
if normalizar_audio and has_audio:
|
| 219 |
extras.append("Γ‘udio normalizado")
|
| 220 |
elif not has_audio:
|
| 221 |
extras.append("β οΈ sem faixa de Γ‘udio")
|
| 222 |
if remover_duplicados:
|
| 223 |
+
extras.append("mpdecimate ativo β decode forΓ§ado na CPU")
|
| 224 |
if gpu_fallback:
|
| 225 |
extras.append("β οΈ GPU indisponΓvel β usou CPU")
|
| 226 |
|
|
|
|
| 231 |
f"ReduΓ§Γ£o : {reducao}%\n"
|
| 232 |
f"FPS : {fps}\n"
|
| 233 |
f"CRF/CQ : {crf_valor}\n"
|
| 234 |
+
f"Codec : {'NVENC (pipeline GPU completo)' if full_gpu_pipeline else 'NVENC (encode GPU)' if use_gpu else 'CPU'}\n"
|
| 235 |
f"Extras : {' | '.join(extras) if extras else 'nenhum'}"
|
| 236 |
)
|
| 237 |
|
|
|
|
| 279 |
normalizar_audio = gr.Checkbox(value=True,
|
| 280 |
label="π Normalizar Γ‘udio (loudnorm -23 LUFS)")
|
| 281 |
remover_duplicados = gr.Checkbox(value=True,
|
| 282 |
+
label="ποΈ Remover frames duplicados (mpdecimate β desative para pipeline GPU completo)")
|
| 283 |
|
| 284 |
btn = gr.Button("π RE-ENCODE AGORA", variant="primary", size="large")
|
| 285 |
|
|
|
|
| 294 |
)
|
| 295 |
|
| 296 |
demo.queue(max_size=5)
|
| 297 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, theme=gr.themes.Soft())
|