Spaces:
Sleeping
Sleeping
File size: 6,383 Bytes
ab496c0 6b4eada ab496c0 d83a342 6b4eada ab496c0 6b4eada d83a342 6b4eada d83a342 6b4eada d83a342 6b4eada d83a342 6b4eada d83a342 6b4eada d83a342 6b4eada d83a342 6b4eada ab496c0 6b4eada d83a342 6b4eada d83a342 ab496c0 6b4eada ab496c0 1f4e0e1 12d32cd ab496c0 1f4e0e1 6b4eada 1f4e0e1 6b4eada 1f4e0e1 12d32cd 6b4eada 12d32cd 6b4eada 12d32cd ab496c0 a79fe10 ab496c0 12d32cd ab496c0 d83a342 8a80570 ab496c0 12d32cd 1f4e0e1 12d32cd ab496c0 1f4e0e1 12d32cd 1f4e0e1 12d32cd 1f4e0e1 12d32cd ab496c0 1f4e0e1 12d32cd ab496c0 1f4e0e1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
import gradio as gr
import subprocess
import tempfile
import os
from pathlib import Path
import json
import shutil
def detect_silence_ffmpeg(video_path, silence_thresh=-40, min_silence_len=1):
"""Detecta silêncio usando FFmpeg diretamente, muito mais rápido que pydub"""
command = [
'ffmpeg', '-i', video_path,
'-af', f'silencedetect=noise={silence_thresh}dB:d={min_silence_len}',
'-f', 'null', '-'
]
# Executa FFmpeg e captura a saída de erro (onde está a informação do silêncio)
result = subprocess.run(command, stderr=subprocess.PIPE, text=True)
# Processa a saída para encontrar timestamps
silence_data = []
start_times = []
end_times = []
for line in result.stderr.split('\n'):
if 'silence_start' in line:
start_time = float(line.split('silence_start: ')[1].split()[0])
start_times.append(start_time)
elif 'silence_end' in line:
end_time = float(line.split('silence_end: ')[1].split()[0])
end_times.append(end_time)
# Cria lista de intervalos não silenciosos
if not start_times:
return []
nonsilent_ranges = []
video_duration = float(get_video_duration(video_path))
# Adiciona segmento do início até o primeiro silêncio
if start_times[0] > 0:
nonsilent_ranges.append((0, start_times[0]))
# Adiciona segmentos entre silêncios
for i in range(len(end_times)):
if i < len(start_times):
nonsilent_ranges.append((end_times[i], start_times[i]))
# Adiciona segmento final se necessário
if end_times and end_times[-1] < video_duration:
nonsilent_ranges.append((end_times[-1], video_duration))
return nonsilent_ranges
def get_video_duration(video_path):
"""Obtém a duração do vídeo usando FFmpeg"""
command = [
'ffprobe', '-v', 'error',
'-show_entries', 'format=duration',
'-of', 'json',
video_path
]
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data = json.loads(result.stdout)
return float(data['format']['duration'])
def create_filter_complex(ranges):
"""Cria o filtro complexo para FFmpeg baseado nos intervalos não silenciosos"""
parts = []
for i, (start, end) in enumerate(ranges):
parts.append(f"[0:v]trim=start={start}:end={end},setpts=PTS-STARTPTS[v{i}]; "
f"[0:a]atrim=start={start}:end={end},asetpts=PTS-STARTPTS[a{i}]")
# Concatena os vídeos
v_list = ''.join(f'[v{i}]' for i in range(len(ranges)))
a_list = ''.join(f'[a{i}]' for i in range(len(ranges)))
concat = f"; {v_list}concat=n={len(ranges)}:v=1:a=0[vout]; "
concat += f"{a_list}concat=n={len(ranges)}:v=0:a=1[aout]"
return ''.join(parts) + concat
def process_video_fast(video_path, silence_thresh=-40, min_silence_len=1):
"""Processa o vídeo removendo silêncio usando FFmpeg diretamente"""
# Detecta intervalos não silenciosos
nonsilent_ranges = detect_silence_ffmpeg(video_path, silence_thresh, min_silence_len)
if not nonsilent_ranges:
return video_path
# Cria arquivo de saída
output_path = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
# Cria filtro complexo
filter_complex = create_filter_complex(nonsilent_ranges)
# Processa o vídeo em uma única passagem
command = [
'ffmpeg', '-i', video_path,
'-filter_complex', filter_complex,
'-map', '[vout]',
'-map', '[aout]',
'-c:v', 'libx264',
'-preset', 'ultrafast', # Mais rápido encoding
'-c:a', 'aac',
'-y',
output_path
]
subprocess.run(command, stderr=subprocess.PIPE)
return output_path
def remove_silence(video_input, silence_duration, silence_threshold):
"""Função para remoção normal de silêncio"""
try:
if video_input is None:
raise ValueError("Por favor, faça upload de um vídeo")
return process_video_fast(
video_input,
silence_thresh=silence_threshold,
min_silence_len=silence_duration
)
except Exception as e:
gr.Error(str(e))
return None
def remove_max_silence(video_input):
"""Função para remoção máxima de silêncio"""
try:
if video_input is None:
raise ValueError("Por favor, faça upload de um vídeo")
return process_video_fast(
video_input,
silence_thresh=-30,
min_silence_len=0.1
)
except Exception as e:
gr.Error(str(e))
return None
# Interface Gradio
with gr.Blocks(title="Removedor de Silêncio de Vídeos") as app:
gr.Markdown("# Removedor de Silêncio de Vídeos")
with gr.Row():
with gr.Column():
video_input = gr.Video(
label="Selecione ou Arraste o Vídeo"
)
with gr.Row():
remove_max_btn = gr.Button("🔇 Remover 100% do Silêncio", variant="primary")
remove_custom_btn = gr.Button("Remover Silêncio Personalizado")
with gr.Group():
gr.Markdown("### Configurações Personalizadas")
silence_duration = gr.Slider(
minimum=0.1,
maximum=5.0,
value=1.0,
step=0.1,
label="Duração Mínima do Silêncio (segundos)"
)
silence_threshold = gr.Slider(
minimum=-60,
maximum=-20,
value=-40,
step=1,
label="Limite de Silêncio (dB)"
)
with gr.Row():
video_output = gr.Video(label="Vídeo Processado")
# Event handlers
remove_max_btn.click(
fn=remove_max_silence,
inputs=[video_input],
outputs=[video_output]
)
remove_custom_btn.click(
fn=remove_silence,
inputs=[
video_input,
silence_duration,
silence_threshold
],
outputs=[video_output]
)
if __name__ == "__main__":
app.launch(show_error=True) |