DHEIVER commited on
Commit
c58d9bb
·
verified ·
1 Parent(s): 6b4eada

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -105
app.py CHANGED
@@ -1,142 +1,110 @@
1
  import gradio as gr
2
- import subprocess
 
 
3
  import tempfile
4
  import os
5
  from pathlib import Path
6
- import json
7
- import shutil
8
 
9
- def detect_silence_ffmpeg(video_path, silence_thresh=-40, min_silence_len=1):
10
- """Detecta silêncio usando FFmpeg diretamente, muito mais rápido que pydub"""
11
-
12
- command = [
13
- 'ffmpeg', '-i', video_path,
14
- '-af', f'silencedetect=noise={silence_thresh}dB:d={min_silence_len}',
15
- '-f', 'null', '-'
16
- ]
17
-
18
- # Executa FFmpeg e captura a saída de erro (onde está a informação do silêncio)
19
- result = subprocess.run(command, stderr=subprocess.PIPE, text=True)
20
-
21
- # Processa a saída para encontrar timestamps
22
- silence_data = []
23
- start_times = []
24
- end_times = []
25
-
26
- for line in result.stderr.split('\n'):
27
- if 'silence_start' in line:
28
- start_time = float(line.split('silence_start: ')[1].split()[0])
29
- start_times.append(start_time)
30
- elif 'silence_end' in line:
31
- end_time = float(line.split('silence_end: ')[1].split()[0])
32
- end_times.append(end_time)
33
-
34
- # Cria lista de intervalos não silenciosos
35
- if not start_times:
36
- return []
 
 
37
 
38
- nonsilent_ranges = []
39
- video_duration = float(get_video_duration(video_path))
40
-
41
- # Adiciona segmento do início até o primeiro silêncio
42
- if start_times[0] > 0:
43
- nonsilent_ranges.append((0, start_times[0]))
44
-
45
- # Adiciona segmentos entre silêncios
46
- for i in range(len(end_times)):
47
- if i < len(start_times):
48
- nonsilent_ranges.append((end_times[i], start_times[i]))
49
-
50
- # Adiciona segmento final se necessário
51
- if end_times and end_times[-1] < video_duration:
52
- nonsilent_ranges.append((end_times[-1], video_duration))
53
-
54
- return nonsilent_ranges
55
-
56
- def get_video_duration(video_path):
57
- """Obtém a duração do vídeo usando FFmpeg"""
58
- command = [
59
- 'ffprobe', '-v', 'error',
60
- '-show_entries', 'format=duration',
61
- '-of', 'json',
62
- video_path
63
- ]
64
- result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
65
- data = json.loads(result.stdout)
66
- return float(data['format']['duration'])
67
 
68
- def create_filter_complex(ranges):
69
- """Cria o filtro complexo para FFmpeg baseado nos intervalos não silenciosos"""
70
- parts = []
71
- for i, (start, end) in enumerate(ranges):
72
- parts.append(f"[0:v]trim=start={start}:end={end},setpts=PTS-STARTPTS[v{i}]; "
73
- f"[0:a]atrim=start={start}:end={end},asetpts=PTS-STARTPTS[a{i}]")
74
-
75
- # Concatena os vídeos
76
- v_list = ''.join(f'[v{i}]' for i in range(len(ranges)))
77
- a_list = ''.join(f'[a{i}]' for i in range(len(ranges)))
78
 
79
- concat = f"; {v_list}concat=n={len(ranges)}:v=1:a=0[vout]; "
80
- concat += f"{a_list}concat=n={len(ranges)}:v=0:a=1[aout]"
81
-
82
- return ''.join(parts) + concat
83
-
84
- def process_video_fast(video_path, silence_thresh=-40, min_silence_len=1):
85
- """Processa o vídeo removendo silêncio usando FFmpeg diretamente"""
86
 
87
- # Detecta intervalos não silenciosos
88
- nonsilent_ranges = detect_silence_ffmpeg(video_path, silence_thresh, min_silence_len)
89
 
90
- if not nonsilent_ranges:
 
91
  return video_path
92
 
93
- # Cria arquivo de saída
94
- output_path = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
 
 
 
 
 
 
95
 
96
- # Cria filtro complexo
97
- filter_complex = create_filter_complex(nonsilent_ranges)
 
98
 
99
- # Processa o vídeo em uma única passagem
100
- command = [
101
- 'ffmpeg', '-i', video_path,
102
- '-filter_complex', filter_complex,
103
- '-map', '[vout]',
104
- '-map', '[aout]',
105
- '-c:v', 'libx264',
106
- '-preset', 'ultrafast', # Mais rápido encoding
107
- '-c:a', 'aac',
108
- '-y',
109
- output_path
110
- ]
111
 
112
- subprocess.run(command, stderr=subprocess.PIPE)
113
  return output_path
114
 
115
  def remove_silence(video_input, silence_duration, silence_threshold):
116
- """Função para remoção normal de silêncio"""
117
  try:
118
  if video_input is None:
119
  raise ValueError("Por favor, faça upload de um vídeo")
120
 
121
- return process_video_fast(
 
 
 
122
  video_input,
123
- silence_thresh=silence_threshold,
124
- min_silence_len=silence_duration
125
  )
126
  except Exception as e:
127
  gr.Error(str(e))
128
  return None
129
 
130
  def remove_max_silence(video_input):
131
- """Função para remoção máxima de silêncio"""
132
  try:
133
  if video_input is None:
134
  raise ValueError("Por favor, faça upload de um vídeo")
135
 
136
- return process_video_fast(
 
137
  video_input,
138
- silence_thresh=-30,
139
- min_silence_len=0.1
140
  )
141
  except Exception as e:
142
  gr.Error(str(e))
 
1
  import gradio as gr
2
+ from moviepy.editor import VideoFileClip, concatenate_videoclips
3
+ import numpy as np
4
+ from scipy.io import wavfile
5
  import tempfile
6
  import os
7
  from pathlib import Path
 
 
8
 
9
+ def detect_silence(audio_array, sample_rate, threshold=0.01, min_silence_len=1000):
10
+ """Detecta períodos de silêncio no áudio"""
11
+ # Converte o threshold para amplitude
12
+ amplitude_threshold = threshold * np.max(np.abs(audio_array))
13
+
14
+ # Calcula a energia do áudio
15
+ energy = np.abs(audio_array)
16
+ if len(energy.shape) > 1:
17
+ energy = np.mean(energy, axis=1)
18
+
19
+ # Encontra regiões não silenciosas
20
+ is_sound = energy > amplitude_threshold
21
+
22
+ # Converte frames para segundos
23
+ frame_length = int(sample_rate * (min_silence_len / 1000))
24
+
25
+ # Suaviza a detecção para evitar cortes muito curtos
26
+ sound_chunks = []
27
+ start = None
28
+
29
+ for i in range(len(is_sound)):
30
+ if start is None and is_sound[i]:
31
+ start = i
32
+ elif start is not None and not is_sound[i]:
33
+ if i - start > frame_length:
34
+ sound_chunks.append((start / sample_rate, i / sample_rate))
35
+ start = None
36
+
37
+ if start is not None:
38
+ sound_chunks.append((start / sample_rate, len(is_sound) / sample_rate))
39
 
40
+ return sound_chunks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ def process_video(video_path, threshold=0.01, min_silence_len=1000):
43
+ """Remove silêncio do vídeo"""
44
+ # Carrega o vídeo
45
+ video = VideoFileClip(video_path)
 
 
 
 
 
 
46
 
47
+ # Extrai o áudio para análise
48
+ audio_array = video.audio.to_soundarray()
49
+ sample_rate = video.audio.fps
 
 
 
 
50
 
51
+ # Detecta regiões não silenciosas
52
+ sound_chunks = detect_silence(audio_array, sample_rate, threshold, min_silence_len)
53
 
54
+ if not sound_chunks:
55
+ video.close()
56
  return video_path
57
 
58
+ # Corta e concatena os segmentos não silenciosos
59
+ clips = []
60
+ for start, end in sound_chunks:
61
+ clip = video.subclip(start, end)
62
+ clips.append(clip)
63
+
64
+ # Concatena os clips
65
+ final_clip = concatenate_videoclips(clips)
66
 
67
+ # Salva o resultado
68
+ output_path = str(Path(video_path).parent / f"processed_{Path(video_path).name}")
69
+ final_clip.write_videofile(output_path)
70
 
71
+ # Limpa os recursos
72
+ video.close()
73
+ final_clip.close()
74
+ for clip in clips:
75
+ clip.close()
 
 
 
 
 
 
 
76
 
 
77
  return output_path
78
 
79
  def remove_silence(video_input, silence_duration, silence_threshold):
80
+ """Interface para remoção normal de silêncio"""
81
  try:
82
  if video_input is None:
83
  raise ValueError("Por favor, faça upload de um vídeo")
84
 
85
+ # Converte o threshold de dB para amplitude relativa
86
+ amplitude_threshold = 10 ** (silence_threshold / 20)
87
+
88
+ return process_video(
89
  video_input,
90
+ threshold=amplitude_threshold,
91
+ min_silence_len=int(silence_duration * 1000)
92
  )
93
  except Exception as e:
94
  gr.Error(str(e))
95
  return None
96
 
97
  def remove_max_silence(video_input):
98
+ """Interface para remoção máxima de silêncio"""
99
  try:
100
  if video_input is None:
101
  raise ValueError("Por favor, faça upload de um vídeo")
102
 
103
+ # Configurações agressivas para máxima remoção
104
+ return process_video(
105
  video_input,
106
+ threshold=0.05, # Mais sensível ao som
107
+ min_silence_len=100 # Remove silêncios mais curtos
108
  )
109
  except Exception as e:
110
  gr.Error(str(e))