import gradio as gr import cv2 import numpy as np import soundfile as sf from scipy.io import wavfile import tempfile import os import subprocess def extract_audio(video_path): """Extrai áudio do vídeo usando ffmpeg""" temp_audio = tempfile.mktemp('.wav') command = [ 'ffmpeg', '-i', video_path, '-ab', '160k', '-ac', '2', '-ar', '44100', '-vn', temp_audio ] subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return temp_audio def detect_silence(audio_path, min_silence_length=1000, silence_threshold=-40): """Detecta períodos de silêncio no áudio""" # Lê o arquivo de áudio sample_rate, audio_data = wavfile.read(audio_path) # Converte para mono se estéreo if len(audio_data.shape) > 1: audio_data = audio_data.mean(axis=1) # Calcula a energia do áudio em janelas window_size = int(sample_rate * (min_silence_length/1000)) overlapping = int(window_size/2) non_silent_ranges = [] start = None for i in range(0, len(audio_data), overlapping): window = audio_data[i:i+window_size] if len(window) < window_size: break energy_db = 10 * np.log10(np.mean(window**2) + 1e-10) if energy_db > silence_threshold: if start is None: start = i elif start is not None: non_silent_ranges.append((start/sample_rate, i/sample_rate)) start = None if start is not None: non_silent_ranges.append((start/sample_rate, len(audio_data)/sample_rate)) return non_silent_ranges def process_video(video_path, min_silence_length=1000, silence_threshold=-40): """Processa o vídeo removendo partes silenciosas""" temp_dir = tempfile.mkdtemp() try: # Extrai áudio audio_path = extract_audio(video_path) # Detecta ranges não silenciosos non_silent_ranges = detect_silence(audio_path, min_silence_length, silence_threshold) if not non_silent_ranges: return None, "Nenhuma parte não-silenciosa detectada no vídeo." # Abre o vídeo cap = cv2.VideoCapture(video_path) fps = cap.get(cv2.CAP_PROP_FPS) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # Prepara o arquivo de saída output_path = os.path.join(temp_dir, "output_video.mp4") fourcc = cv2.VideoWriter_fourcc(*'mp4v') out = cv2.VideoWriter(output_path, fourcc, fps, (width, height)) # Processa cada range não silencioso for start_time, end_time in non_silent_ranges: start_frame = int(start_time * fps) end_frame = int(end_time * fps) cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame) for _ in range(end_frame - start_frame): ret, frame = cap.read() if not ret: break out.write(frame) cap.release() out.release() # Adiciona áudio ao vídeo final final_path = os.path.join(temp_dir, "final_output.mp4") command = [ 'ffmpeg', '-i', output_path, '-i', audio_path, '-c:v', 'copy', '-c:a', 'aac', final_path ] subprocess.call(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return final_path, "Vídeo processado com sucesso!" except Exception as e: return None, f"Erro ao processar vídeo: {str(e)}" finally: # Limpa arquivos temporários for file in os.listdir(temp_dir): try: os.remove(os.path.join(temp_dir, file)) except: pass try: os.rmdir(temp_dir) except: pass def create_interface(): with gr.Blocks(theme=gr.themes.Soft()) as iface: gr.Markdown( """ # 🎬 Video Silence Trimmer Remove momentos de silêncio de seus vídeos automaticamente. """ ) with gr.Row(): with gr.Column(): input_video = gr.Video(label="Vídeo de Entrada") with gr.Row(): silence_threshold = gr.Slider( minimum=-60, maximum=-20, value=-40, step=1, label="Limiar de Silêncio (dB)", info="Quanto menor o valor, mais sensível à detecção de silêncio" ) min_silence = gr.Slider( minimum=100, maximum=3000, value=1000, step=100, label="Duração Mínima do Silêncio (ms)", info="Duração mínima para considerar um trecho como silêncio" ) process_btn = gr.Button("Processar Vídeo", variant="primary") with gr.Column(): output_video = gr.Video(label="Vídeo Processado") status_text = gr.Textbox(label="Status", interactive=False) process_btn.click( fn=process_video, inputs=[input_video, min_silence, silence_threshold], outputs=[output_video, status_text] ) gr.Markdown( """ ### Como usar: 1. Faça upload do seu vídeo 2. Ajuste os parâmetros de detecção de silêncio se necessário 3. Clique em "Processar Vídeo" 4. Aguarde o processamento e baixe o resultado ### Dicas: - Ajuste o "Limiar de Silêncio" para maior sensibilidade na detecção - Use a "Duração Mínima do Silêncio" para ignorar pausas muito curtas """ ) return iface if __name__ == "__main__": iface = create_interface() iface.launch(share=True)