WebRTC VAD采样率错误排查:YouTube视频翻译工具问题
YouTube视频翻译工具:采样率错误修复、背景音保留与音频对齐方案
采样率错误核心修复
报错「Sample rate must be 8k, 16k, 32k, or 48k」是因为WebRTC VAD和Whisper对输入音频采样率有严格限制,你的流程中提取/转码音频时可能输出了非标准采样率(比如22050Hz)。以下是两种直接修复方式:
1. 下载/转码时强制指定16kHz采样率(最优兼容值)
用yt-dlp下载时直接转码为符合要求的音频:
yt-dlp -x --audio-format wav --audio-quality 0 --postprocessor-args "-ar 16000 -ac 1" [YouTube视频URL]
如果是处理已下载的音频文件,用ffmpeg转码:
ffmpeg -i input_audio.wav -ar 16000 -ac 1 output_16k_mono.wav
2. 代码中动态转换采样率
用Python处理音频时,强制将采样率统一为16kHz:
import librosa import soundfile as sf # 加载音频并自动转换为16kHz单声道 audio, sr = librosa.load("input_audio.wav", sr=16000, mono=True) sf.write("processed_audio.wav", audio, 16000)
保留原视频背景音的实现逻辑
要保留背景音,需区分语音段和非语音段,仅替换语音部分:
- 提取背景音:将原音频中所有语音段静音,保留其余背景音
# 假设已生成语音段时间戳文件timestamps.txt(每行格式:start,end) ffmpeg -i original_video.mp4 -filter_complex "[0:a]volume=0:enable='between(t,0.5,2.3)+between(t,5.1,7.8)'" background_audio.wav - 拼接翻译音频:将生成的翻译音频按原语音段时间戳,精确覆盖到背景音的对应位置
批量处理可通过脚本循环生成ffmpeg滤镜参数,确保仅在原语音时段播放翻译音频。
音频与视频完美对齐关键
- 提升VAD分割精度:将WebRTC VAD设置为最严格模式,减少误判
from webrtcvad import Vad vad = Vad(3) # 模式3:最严格,适合精确分割语音边界 - 获取精确时间戳:用Whisper的
word_timestamps=True参数,获取单词级别的起止时间,用于匹配原语音时长import whisper model = whisper.load_model("base") result = model.transcribe("processed_audio.wav", word_timestamps=True) # 从result中提取每个语音段的精确起止时间 - 匹配翻译音频时长:生成翻译音频时,调整语速使其与原语音段时长完全一致(比如用Coqui TTS的
speed参数) - 同步音视频轨道:最后用ffmpeg合并时直接复用原视频编码,仅替换音频轨道:
ffmpeg -i original_video.mp4 -i final_audio.wav -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output_video.mp4
调整后的核心代码片段
import yt_dlp import ffmpeg from webrtcvad import Vad import whisper from TTS.api import TTS import librosa # 1. 下载并转码为16kHz单声道音频 ydl_opts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'wav', 'preferredquality': '0', }], 'postprocessor_args': ['-ar', '16000', '-ac', '1'], 'outtmpl': 'downloaded_audio.wav', } with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download(['https://www.youtube.com/watch?v=example']) # 2. WebRTC VAD分割语音段(采样率已确保为16k) vad = Vad(3) audio, sr = librosa.load('downloaded_audio.wav', sr=16000, mono=True) timestamps = [] # 存储每个语音段的(start, end)时间对 # 此处添加VAD分割逻辑,填充timestamps... # 3. Whisper转录并获取时间戳 model = whisper.load_model('base') result = model.transcribe('downloaded_audio.wav', word_timestamps=True) original_texts = [segment['text'] for segment in result['segments']] # 4. 翻译文本(示例用Hugging Face翻译模型) from transformers import pipeline translator = pipeline('translation', model='Helsinki-NLP/opus-mt-en-zh') translated_texts = [translator(text)[0]['translation_text'] for text in original_texts] # 5. 生成匹配原时长的翻译音频 tts = TTS(model_name="tts_models/zh-CN/baker/tacotron2-DDC-GST") for idx, (text, start, end) in enumerate(zip(translated_texts, timestamps)): original_duration = end - start # 估算语速并生成对应时长的音频 temp_audio_path = f'temp_{idx}.wav' tts.tts_to_file(text=text, file_path=temp_audio_path) temp_duration = librosa.get_duration(filename=temp_audio_path) speed = temp_duration / original_duration tts.tts_to_file(text=text, file_path=f'translated_segment_{idx}.wav', speed=speed) # 6. 合成背景音与翻译音频(简化示例,批量需优化滤镜逻辑) # 生成背景音 filter_str = "+".join([f"between(t,{s},{e})" for s,e in timestamps]) ffmpeg.input('downloaded_audio.wav').filter('volume', 0, enable=filter_str).output('background_audio.wav').run() # 合并音频(批量处理需动态生成滤镜参数) merge_inputs = [ffmpeg.input('background_audio.wav')] filter_parts = [] for idx in range(len(timestamps)): seg_input = ffmpeg.input(f'translated_segment_{idx}.wav') merge_inputs.append(seg_input) s, e = timestamps[idx] filter_parts.append(f"[{idx+1}:a]volume=1:enable='between(t,{s},{e})';") filter_parts.append("[0:a]" + "".join([f"[{i+1}:a]" for i in range(len(timestamps))]) + f"amix=inputs={len(timestamps)+1}") ffmpeg.concat(*merge_inputs, filter_complex=" ".join(filter_parts)).output('final_audio.wav').run() # 7. 替换视频音频 ffmpeg.input('original_video.mp4').input('final_audio.wav').output('output_video.mp4', vcodec='copy', acodec='aac').run()
内容的提问来源于stack exchange,提问作者VishIsHere26
相关产品推荐
相关产品推荐

