DHEIVER commited on
Commit
d83a342
·
verified ·
1 Parent(s): 762babc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -34
app.py CHANGED
@@ -4,30 +4,76 @@ from pydub import AudioSegment
4
  from pydub.silence import detect_nonsilent
5
  import tempfile
6
  import os
 
 
 
 
7
 
8
- def process_video(video_path, min_silence_len=1000, silence_thresh=-40):
9
- """
10
- Remove segmentos silenciosos do vídeo.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- Args:
13
- video_path: Caminho do arquivo de vídeo
14
- min_silence_len: Duração mínima do silêncio em ms
15
- silence_thresh: Limite de dB para detectar silêncio
 
 
 
 
 
 
 
 
 
16
  """
17
- # Criar diretório temporário para arquivos processados
 
 
18
  temp_dir = tempfile.mkdtemp()
19
 
20
- # Carregar o vídeo
21
- video = mp.VideoFileClip(video_path)
22
-
23
- # Extrair áudio para arquivo temporário
24
  temp_audio = os.path.join(temp_dir, "temp_audio.wav")
25
- video.audio.write_audiofile(temp_audio)
26
-
27
- # Carregar áudio com pydub
28
- audio = AudioSegment.from_wav(temp_audio)
29
 
30
  # Detectar segmentos não silenciosos
 
31
  nonsilent_ranges = detect_nonsilent(
32
  audio,
33
  min_silence_len=min_silence_len,
@@ -37,45 +83,66 @@ def process_video(video_path, min_silence_len=1000, silence_thresh=-40):
37
  if not nonsilent_ranges:
38
  return video_path
39
 
40
- # Converter timestamps para segundos
41
  nonsilent_ranges_sec = [(start/1000.0, end/1000.0) for start, end in nonsilent_ranges]
42
 
43
- # Cortar e concatenar segmentos não silenciosos
44
- clips = [video.subclip(start, end) for start, end in nonsilent_ranges_sec]
45
- final_clip = mp.concatenate_videoclips(clips)
 
 
 
 
 
 
 
 
46
 
47
- # Salvar vídeo processado
48
  output_path = os.path.join(temp_dir, "processed_video.mp4")
49
- final_clip.write_videofile(output_path)
50
 
51
- # Limpar
52
- video.close()
53
- os.remove(temp_audio)
54
 
55
- return output_path
 
 
 
56
 
57
  def remove_silence(video, silence_duration, silence_threshold):
58
  if video is None:
59
  return None
60
 
61
  try:
62
- processed_video = process_video(
63
- video,
64
- min_silence_len=int(silence_duration * 1000), # Converter para ms
65
- silence_thresh=silence_threshold
66
- )
 
 
 
67
  return processed_video
68
  except Exception as e:
69
  return str(e)
70
 
71
- # Interface Gradio
72
  with gr.Blocks(title="Removedor de Silêncio de Vídeos") as app:
73
  gr.Markdown("# Removedor de Silêncio de Vídeos")
74
- gr.Markdown("Faça upload de um vídeo e ajuste os parâmetros para remover segmentos silenciosos.")
 
 
 
 
75
 
76
  with gr.Row():
77
  with gr.Column():
78
- video_input = gr.Video(label="Vídeo de Entrada")
 
 
 
79
  silence_duration = gr.Slider(
80
  minimum=0.1,
81
  maximum=5.0,
 
4
  from pydub.silence import detect_nonsilent
5
  import tempfile
6
  import os
7
+ import subprocess
8
+ from concurrent.futures import ThreadPoolExecutor
9
+ import shutil
10
+ from pathlib import Path
11
 
12
+ def extract_audio_ffmpeg(video_path, output_path):
13
+ """Extrai áudio usando FFmpeg diretamente para maior velocidade"""
14
+ command = [
15
+ 'ffmpeg', '-i', video_path,
16
+ '-vn', # Pula o vídeo
17
+ '-acodec', 'pcm_s16le', # Formato de áudio
18
+ '-ar', '44100', # Sample rate
19
+ '-ac', '2', # Canais
20
+ '-y', # Sobrescreve arquivo se existir
21
+ output_path
22
+ ]
23
+ subprocess.run(command, stderr=subprocess.PIPE)
24
+
25
+ def cut_video_ffmpeg(input_path, output_path, start, end):
26
+ """Corta vídeo usando FFmpeg diretamente"""
27
+ command = [
28
+ 'ffmpeg', '-i', input_path,
29
+ '-ss', str(start),
30
+ '-t', str(end - start),
31
+ '-c', 'copy', # Usa codec copying para maior velocidade
32
+ '-avoid_negative_ts', '1',
33
+ '-y',
34
+ output_path
35
+ ]
36
+ subprocess.run(command, stderr=subprocess.PIPE)
37
+
38
+ def process_video_chunk(args):
39
+ """Processa um chunk do vídeo"""
40
+ input_path, output_path, start, end = args
41
+ cut_video_ffmpeg(input_path, output_path, start, end)
42
+ return output_path
43
+
44
+ def concatenate_videos_ffmpeg(video_list, output_path):
45
+ """Concatena vídeos usando FFmpeg"""
46
+ # Cria arquivo de lista
47
+ list_file = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt')
48
+ for video in video_list:
49
+ list_file.write(f"file '{video}'\n")
50
+ list_file.close()
51
 
52
+ # Concatena usando FFmpeg
53
+ command = [
54
+ 'ffmpeg', '-f', 'concat',
55
+ '-safe', '0',
56
+ '-i', list_file.name,
57
+ '-c', 'copy',
58
+ '-y',
59
+ output_path
60
+ ]
61
+ subprocess.run(command, stderr=subprocess.PIPE)
62
+ os.unlink(list_file.name)
63
+
64
+ def process_video(video_path, min_silence_len=1000, silence_thresh=-40, max_workers=4):
65
  """
66
+ Remove segmentos silenciosos do vídeo com processamento otimizado.
67
+ """
68
+ # Criar diretório temporário
69
  temp_dir = tempfile.mkdtemp()
70
 
71
+ # Extrair áudio
 
 
 
72
  temp_audio = os.path.join(temp_dir, "temp_audio.wav")
73
+ extract_audio_ffmpeg(video_path, temp_audio)
 
 
 
74
 
75
  # Detectar segmentos não silenciosos
76
+ audio = AudioSegment.from_wav(temp_audio)
77
  nonsilent_ranges = detect_nonsilent(
78
  audio,
79
  min_silence_len=min_silence_len,
 
83
  if not nonsilent_ranges:
84
  return video_path
85
 
86
+ # Converter para segundos
87
  nonsilent_ranges_sec = [(start/1000.0, end/1000.0) for start, end in nonsilent_ranges]
88
 
89
+ # Preparar argumentos para processamento paralelo
90
+ chunk_args = []
91
+ chunk_outputs = []
92
+ for i, (start, end) in enumerate(nonsilent_ranges_sec):
93
+ output_chunk = os.path.join(temp_dir, f"chunk_{i}.mp4")
94
+ chunk_args.append((video_path, output_chunk, start, end))
95
+ chunk_outputs.append(output_chunk)
96
+
97
+ # Processar chunks em paralelo
98
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
99
+ list(executor.map(process_video_chunk, chunk_args))
100
 
101
+ # Concatenar todos os chunks
102
  output_path = os.path.join(temp_dir, "processed_video.mp4")
103
+ concatenate_videos_ffmpeg(chunk_outputs, output_path)
104
 
105
+ # Criar cópia do resultado em local permanente
106
+ final_output = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
107
+ shutil.copy2(output_path, final_output)
108
 
109
+ # Limpar arquivos temporários
110
+ shutil.rmtree(temp_dir)
111
+
112
+ return final_output
113
 
114
  def remove_silence(video, silence_duration, silence_threshold):
115
  if video is None:
116
  return None
117
 
118
  try:
119
+ with gr.Progress() as progress:
120
+ progress(0, desc="Iniciando processamento...")
121
+ processed_video = process_video(
122
+ video,
123
+ min_silence_len=int(silence_duration * 1000),
124
+ silence_thresh=silence_threshold
125
+ )
126
+ progress(1, desc="Processamento concluído!")
127
  return processed_video
128
  except Exception as e:
129
  return str(e)
130
 
131
+ # Interface Gradio com indicador de progresso
132
  with gr.Blocks(title="Removedor de Silêncio de Vídeos") as app:
133
  gr.Markdown("# Removedor de Silêncio de Vídeos")
134
+ gr.Markdown("""
135
+ ### Otimizado para processamento rápido
136
+ Faça upload de um vídeo e ajuste os parâmetros para remover segmentos silenciosos.
137
+ O processamento é feito em paralelo para maior velocidade.
138
+ """)
139
 
140
  with gr.Row():
141
  with gr.Column():
142
+ video_input = gr.Video(
143
+ label="Vídeo de Entrada",
144
+ type="filepath" # Usar filepath para upload mais rápido
145
+ )
146
  silence_duration = gr.Slider(
147
  minimum=0.1,
148
  maximum=5.0,