Spaces:
Sleeping
Sleeping
File size: 5,620 Bytes
ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 d83a342 ab496c0 |
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 |
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', 'copy', # Usa codec copying para maior velocidade
'-avoid_negative_ts', '1',
'-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()
# Concatena usando FFmpeg
command = [
'ffmpeg', '-f', 'concat',
'-safe', '0',
'-i', list_file.name,
'-c', 'copy',
'-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.
"""
# Criar diretório temporário
temp_dir = tempfile.mkdtemp()
# Extrair áudio
temp_audio = os.path.join(temp_dir, "temp_audio.wav")
extract_audio_ffmpeg(video_path, temp_audio)
# Detectar segmentos não silenciosos
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 argumentos para processamento paralelo
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 todos os chunks
output_path = os.path.join(temp_dir, "processed_video.mp4")
concatenate_videos_ffmpeg(chunk_outputs, output_path)
# Criar cópia do resultado em local permanente
final_output = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
shutil.copy2(output_path, final_output)
# Limpar arquivos temporários
shutil.rmtree(temp_dir)
return final_output
def remove_silence(video, silence_duration, silence_threshold):
if video is None:
return None
try:
with gr.Progress() as progress:
progress(0, desc="Iniciando processamento...")
processed_video = process_video(
video,
min_silence_len=int(silence_duration * 1000),
silence_thresh=silence_threshold
)
progress(1, desc="Processamento concluído!")
return processed_video
except Exception as e:
return str(e)
# Interface Gradio com indicador de progresso
with gr.Blocks(title="Removedor de Silêncio de Vídeos") as app:
gr.Markdown("# Removedor de Silêncio de Vídeos")
gr.Markdown("""
### Otimizado para processamento rápido
Faça upload de um vídeo e ajuste os parâmetros para remover segmentos silenciosos.
O processamento é feito em paralelo para maior velocidade.
""")
with gr.Row():
with gr.Column():
video_input = gr.Video(
label="Vídeo de Entrada",
type="filepath" # Usar filepath para upload mais rápido
)
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)"
)
process_btn = gr.Button("Processar Vídeo")
with gr.Column():
video_output = gr.Video(label="Vídeo Processado")
process_btn.click(
fn=remove_silence,
inputs=[video_input, silence_duration, silence_threshold],
outputs=video_output
)
if __name__ == "__main__":
app.launch() |