手撸个视频翻译和配音工具玩玩 结果不太妙

近来得空研究了下视频翻译,即将某种语言的视频处理后,显示另一种语言的字幕并使用该语言进行配音。

原本只打算语音识别转为文字后,生成字幕就完结了,因为实在没有找到满足"自然音色、准确度好、容易安装"这些条件的好的语音合成方案,比如facebook的 facebook seamless_communication mozilla/TTS , 又从 huggingface.co/ 找了不少模型,结果都不理想,貌似除了针对性训练,其他效果都很差,不具备可用性。

百度语音、讯飞等国内api只能提供中英语言,而无法提供其他语言比如日语、韩语等。

Azuer googleCloud 的效果还不错,可惜不面向国内服务,购买或免费试用都过于困难。

这几天突然想到,edge浏览器自带语音朗读功能,一般 win10 win11 上自带安装edge,直接调用 edge tts 不就得了呗。

说干就干,github上搜索了些 edge-tts相关项目,参考了下,将之前未完成的语音配音继续完成。

整体思路如下:

工具 python3.10 + ffmpeg

从视频中提取出音频,然后将音频切割分段,对音频进行语音识别得到文字,并记录起始时间戳,将文字调用翻译接口,翻译为想要的语言文字,整理为srt字幕文件。

再将翻译后的语言文字,通过语音合成接口,生成相应语音片段,最后将语音片段、字幕和删掉音频轨道的视频合并,生成翻译后的视频

语音识别和文字翻译使用google接口,文字合成语音使用 Microsoft Edge tts,无需购买任何商业接口,也无需付费

  1. 原始mp4视频使用 ffmpeg 提取出音频,ffmpeg 命令如下

    css 复制代码
    ffmpeg -i 1.mp4 -acodec pcm_s16le -f s16le -ac 1 -ar 16000 -f wav audio.wav
  2. 将音频文件按照静音片段分隔为最大不超过60s的小片段,以方便识别,使用pydub库进行,先安装 pip install pydub

ini 复制代码
pydub.silence.detect_nonsilent(normalized_sound, 
min_silence_len=min_slien, 
silence_thresh=-20.0 - thd,
seek_step=1)
  1. 调用google的语音识别库进行,直接 pip install SpeechRecognition ,可避免再去申请google cloud key,里面自带一个测试key,至少目前来说,并没发现频率和用量方面的限制,关键命令
ini 复制代码
r=speech_recognition.Recognizer()
text = r.recognize_google(audio_listened, language="en")

text 即为识别到的文本。

  1. 根据识别到的文本,再调用google翻译api翻译为所需语言的文字
ini 复制代码
translator = Translator(service_urls=['translate.googleapis.com'])
transd = translator.translate(text, src="en",dest="zh-cn")

这里需要安装google翻译python库,同样无需申请api key。 pip install googletrans

  1. 使用 srt 库 pip install srt 合并获取到的文字为srt格式字幕
sql 复制代码
sub = srt.Subtitle(index=index, start=start, end=end, content=text)
  1. 到此字幕文件完成了。调用ffmpeg合成即搞定了字幕翻译
css 复制代码
ffmpeg -y -i {source_mp4} -i {sub_name} -c copy -c:s mov_text -metadata:s:s:0 language={video_config['subtitle_language']}  {target_mp4}
  1. 还想继续生成配音,那么继续安装 edge-tts pip install edge-tts,将翻译后的每段文本依次交给edge_tts 进行合成,合成后临时创建mp3音频,将该音频使用pydub转为合适的数据格式,存在segments列表中,同时记录下每段文本位于原音频中的开始时间 start_time 放入 start_times 列表中,关键代码如下
ini 复制代码
communicate = edge_tts.Communicate(result, "配音角色名", rate="加减语速")
tmpname = f"./tmp/{start_time}-{index}.mp3"
asyncio.run(communicate.save(tmpname))
audio_data = AudioSegment.from_file(tmpname, format="mp3")
segments.append(audio_data)
start_times.append(start_time)

最后将合成后的所有语音片段连接

ini 复制代码
# 拼接配音片段
def merge_audio_segments(segments, start_times, total_duration, mp4name):
    # 创建一个空白的音频段作为初始片段
    merged_audio = AudioSegment.empty()
    # 检查是否需要在第一个片段之前添加静音
    if start_times[0] != 0:
        silence_duration = start_times[0]
        silence = AudioSegment.silent(duration=silence_duration)
        merged_audio += silence

    # 逐个连接音频片段
    for i in range(len(segments)):
        segment = segments[i]
        start_time = start_times[i]
        # 检查前一个片段的结束时间与当前片段的开始时间之间是否有间隔
        if i > 0:
            previous_end_time = start_times[i - 1] + len(segments[i - 1])
            silence_duration = start_time - previous_end_time
            # 可能存在字幕 语音对应问题
            if silence_duration > 0:
                silence = AudioSegment.silent(duration=silence_duration)
                merged_audio += silence

        # 连接当前片段
        merged_audio += segment
    # 检查总时长是否大于指定的时长,并丢弃多余的部分
    if len(merged_audio) > total_duration:
        merged_audio = merged_audio[:total_duration]
    merged_audio.export(f"./tmp/{mp4name}.wav", format="wav")
    return merged_audio
  1. 将原视频删掉音频轨道
go 复制代码
ffmpeg.exe -i videoWithAudio.mp4 -map 0 -map 0:a:1 -copy novoice.mp4

然后添加上面合成后的新音频

go 复制代码
ffmpeg -y -i novoice.mp4 -i hecheng.wav -c copy -map 0:v:0 -map 1:a:0 voiceandvideo.mp4 
  1. 合成后的新视频再添加字幕srt
css 复制代码
ffmpeg -y -i voiceandvideo -i zimu.srt -c copy -c:s mov_text -metadata:s:s:0 language=zh-cn  allend.mp4

至此完成。字幕效果看起来还凑合,语音效果勉强也能接受。作为低层本方案玩玩可还行。


遇到不少坑

  1. google代理的问题。由于都懂的缘故,无法访问google,不得不配置代理,但 googletrans 库在代理支持下貌似存在问题,只好安装googletrans 3.1.0a0版本,然后将 lib/googletrans/client.py 中的proxies类型改为
python 复制代码
proxies: typing.Dict[str, httpcore.SyncHTTPProxy] = None,

在程序启动脚本中修改环境变量

css 复制代码
os.environ['http_proxy'] = proxy
os.environ['https_proxy'] = proxy

设置系统代理

  1. ffmepg同样也是直接放在工程目录下,然后通过修改 os.environ['path'] 的方式直接定位

  2. 声画不对齐的问题。

    同样一句话,使用中文和使用英文大概率所需时间是不同的,这就导致原本5s的声音片段转为其他语言后变成了10s或者相反。因此加入了语速调整,根据需要可降低或增加语速。然而效果还是不尽如人意,有时中文很短的一句话,英文却说半天。看了其他方案,基本都是在配音加入视频前,允许用户手动调整时间线再次对齐,作为用爱发电的项目,就省略了这麻烦的一步。

  3. 不对齐的问题也会出现在字幕和声音上,主要是音频切割导致的,音频一般按照固定时间切分,或者按照静音片段切分,但前者可能导致一句话未说完就被分开;后者在长时间没有足够静音片段时,可能导致某段太长,不得不强制分割,或者存在背景音时,会无法准确识别到文字。(这里不得不吐槽下,很多老外说话机关枪似的,在1分钟内500ms的停顿时间都很难找)。

  4. 当前解决方案是:遇到某些片段无法识别,就直接跳过复制原始音频片段,所以翻译后的视频中可能仍存在原语音,尤其是在存在背景音乐和背景噪声时。 尝试通过 noisereduce 库降噪,但效果更糟糕,暂时放弃。

ini 复制代码
# 尝试用过的降噪方法
from noisereduce import reduce_noise
audio_array = audio.get_array_of_samples() 
reduced_noise = reduce_noise(audio_array, audio.frame_rate) 

reduced_audio = AudioSegment( reduced_noise.tobytes(), frame_rate=audio.frame_rate, sample_width=audio.sample_width, channels=audio.channels )

使用 tkinter 包装个GUI界面

  1. 使用py自带的标准GUI库 tkinter 简单包装了下,为布局方便,又使用了 tkinter 的包装库 PySimpleGUI
  2. 使用 pyinstaller 打包exe pyinstall -w sp.py

GUI界面

效果

原视频 翻译后视频

翻译后的视频如预料中一样,中间某些片段无法识别或无法合成,就直接复制了原音频片段,效果不理想。 改进方法还是需要通过降噪、去除背景音乐等方式提高识别准确度,但目前尚未找到"无需训练、无需安装庞大模块"的合适方案。

github源码

github.com/jianchang51...

使用或参考的开源项目

github.com/jiaaro/pydu...

github.com/rany2/edge-...

github.com/facebookres...

github.com/coqui-ai/TT...

相关推荐
码事漫谈4 分钟前
AI行业热点抓取和排序系统实现案例
后端
我要学习别拦我~11 分钟前
kaggle分析项目:steam付费游戏数据分析
python·游戏·数据分析
方圆想当图灵12 分钟前
关于 Nacos 在 war 包部署应用关闭部分资源未释放的原因分析
后端
大模型真好玩17 分钟前
深入浅出LangChain AI Agent智能体开发教程(四)—LangChain记忆存储与多轮对话机器人搭建
前端·人工智能·python
love530love19 分钟前
命令行创建 UV 环境及本地化实战演示—— 基于《Python 多版本与开发环境治理架构设计》的最佳实践
开发语言·人工智能·windows·python·conda·uv
Lemon程序馆23 分钟前
今天聊聊 Mysql 的那些“锁”事!
后端·mysql
龙卷风040525 分钟前
使用本地IDEA连接服务器远程构建部署Docker服务
后端·docker
vv安的浅唱30 分钟前
Golang基础笔记七之指针,值类型和引用类型
后端·go