Spaces:
Sleeping
Sleeping
File size: 6,935 Bytes
ab496c0 d83a342 ab496c0 d83a342 8a80570 d83a342 8a80570 d83a342 ab496c0 d83a342 8a80570 d83a342 12d32cd 1f4e0e1 ab496c0 a79fe10 8a80570 a79fe10 8a80570 a79fe10 8a80570 a79fe10 8a80570 a79fe10 8a80570 a79fe10 8a80570 a79fe10 8a80570 a79fe10 d83a342 1f4e0e1 a79fe10 ab496c0 1f4e0e1 12d32cd ab496c0 1f4e0e1 12d32cd 1f4e0e1 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 198 199 200 201 202 203 204 205 206 207 208 209 |
import gradio as gr
import moviepy.editor as mp
from pydub import AudioSegment
from pydub.silence import detect_nonsilent
import tempfile
import os
import subprocess
from concurrent.futures import ThreadPoolExecutor
import shutil
from pathlib import Path
def extract_audio_ffmpeg(video_path, output_path):
"""Extrai áudio usando FFmpeg diretamente para maior velocidade"""
command = [
'ffmpeg', '-i', video_path,
'-vn', # Pula o vídeo
'-acodec', 'pcm_s16le', # Formato de áudio
'-ar', '44100', # Sample rate
'-ac', '2', # Canais
'-y', # Sobrescreve arquivo se existir
output_path
]
subprocess.run(command, stderr=subprocess.PIPE)
def cut_video_ffmpeg(input_path, output_path, start, end):
"""Corta vídeo usando FFmpeg diretamente"""
command = [
'ffmpeg', '-i', input_path,
'-ss', str(start),
'-t', str(end - start),
'-c:v', 'libx264', # Codec de vídeo
'-c:a', 'aac', # Codec de áudio
'-strict', 'experimental',
'-y',
output_path
]
subprocess.run(command, stderr=subprocess.PIPE)
def process_video_chunk(args):
"""Processa um chunk do vídeo"""
input_path, output_path, start, end = args
cut_video_ffmpeg(input_path, output_path, start, end)
return output_path
def concatenate_videos_ffmpeg(video_list, output_path):
"""Concatena vídeos usando FFmpeg"""
# Cria arquivo de lista
list_file = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt')
for video in video_list:
list_file.write(f"file '{video}'\n")
list_file.close()
command = [
'ffmpeg', '-f', 'concat',
'-safe', '0',
'-i', list_file.name,
'-c:v', 'libx264', # Codec de vídeo
'-c:a', 'aac', # Codec de áudio
'-strict', 'experimental',
'-y',
output_path
]
subprocess.run(command, stderr=subprocess.PIPE)
os.unlink(list_file.name)
def process_video(video_path, min_silence_len=1000, silence_thresh=-40, max_workers=4):
"""Remove segmentos silenciosos do vídeo com processamento otimizado."""
if not os.path.exists(video_path):
raise ValueError("Arquivo de vídeo não encontrado")
temp_dir = tempfile.mkdtemp()
try:
# Extrair áudio para análise
temp_audio = os.path.join(temp_dir, "temp_audio.wav")
extract_audio_ffmpeg(video_path, temp_audio)
# Analisar áudio para detectar silêncio
audio = AudioSegment.from_wav(temp_audio)
nonsilent_ranges = detect_nonsilent(
audio,
min_silence_len=min_silence_len,
silence_thresh=silence_thresh
)
if not nonsilent_ranges:
return video_path
# Converter para segundos
nonsilent_ranges_sec = [(start/1000.0, end/1000.0) for start, end in nonsilent_ranges]
# Preparar chunks de vídeo
chunk_args = []
chunk_outputs = []
for i, (start, end) in enumerate(nonsilent_ranges_sec):
output_chunk = os.path.join(temp_dir, f"chunk_{i}.mp4")
chunk_args.append((video_path, output_chunk, start, end))
chunk_outputs.append(output_chunk)
# Processar chunks em paralelo
with ThreadPoolExecutor(max_workers=max_workers) as executor:
list(executor.map(process_video_chunk, chunk_args))
# Concatenar chunks
output_path = os.path.join(temp_dir, "processed_video.mp4")
concatenate_videos_ffmpeg(chunk_outputs, output_path)
# Copiar resultado final
final_output = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
shutil.copy2(output_path, final_output)
return final_output
except Exception as e:
raise Exception(f"Erro ao processar vídeo: {str(e)}")
finally:
shutil.rmtree(temp_dir)
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")
processed_video = process_video(
video_input,
min_silence_len=int(silence_duration * 1000),
silence_thresh=silence_threshold
)
return processed_video
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")
# Configurações mais agressivas para detectar todo silêncio
processed_video = process_video(
video_input,
min_silence_len=100, # Detecta silêncios de 0.1 segundos
silence_thresh=-30 # Limite mais alto para detectar mais silêncio
)
return processed_video
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():
# Botão para remoção máxima de silêncio
remove_max_btn = gr.Button("🔇 Remover 100% do Silêncio", variant="primary")
# Botão para remoção personalizada
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) |