DHEIVER's picture
Update app.py
d83a342 verified
raw
history blame
5.62 kB
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()