试想一下,当我们在观看一段视频时,如果遇上字幕缺失,观感是不是会大打折扣?
近些年,短视频、直播等线上娱乐方式快速发展,直接拉动了旅游、电商、影视创作等行业新风潮;而要呈现出一段好的视频效果,不仅仅考验好的拍摄技法,后期处理也是重中之重。以视频字幕为例,有字幕的视频总能“一气呵成”的顺畅看完,而无字幕的,总令人觉得缺失了一种味道。事实上,纯手工添加字幕,也费时费力,面对较大时长与批量化字幕处理的,多少有些苦不堪言,那有没有更智能化的方式呢?
接下来,本文将分享一下,如何借助录音文件识别服务给无字幕视频自动生成字幕。
(资料图)
给无字幕视频自动生成字幕,其实就是先对视频文件导出的音频文件进行识别,得到识别文字,再根据识别得到的文字与短句的时间信息处理得到视频srt字幕文件,在视频文件中导入srt字幕文件即可得到效果。
实现思路如下:
1.借助ffmpeg从视频中提取音频
2.调用录音文件识别服务,对音频文件进行识别
3.对识别得到的文字与短句的时间信息进行处理得到视频srt字幕文件
4.将命名相同的视频文件与srt文件放在同一目录下,用暴风影音或其他播放器打开,即可得到有字幕的视频。
项目使用了ffmpeg依赖,需先下载安装,并设置环境变量。之后就可通过引入subprocess库,执行ffmpeg命令,启动一个新进程,完成对音频的提取。
import subprocessdef extract_audio(video, tmpAudio):ret = subprocess.run("ffmpeg -version", shell=True)if ret.returncode != 0:print("请先安装 ffmpeg 依赖 ,并设置环境变量")returnret = subprocess.check_call(["ffmpeg", "-i", video, "-vn", "-ar", "16000", tmpAudio], shell=False)if ret.returncode != 0:print("error:", ret)
在这里笔者选择的录音文件识别服务是腾讯云ASR的录音文件识别,通过调研,腾讯云的录音文件识别,可以在调用时直接根据语句之间的停顿智能断句、加标点,无需再调用其他接口进行语句拆分,同时返回结果数据也可根据不同需求进行多种选择,如是否过滤脏词、是否过滤语气词等。
服务具体详细信息这里不再赘述,详情见官方文档见腾讯云ASR。
(1)要访问腾讯云的服务,则需要SecertId与SecretKey,该API密钥可在API密钥管理页面新建与查询,稍后配置到config文件中即可。
笔者项目配置在tencent/config.py当中
class Config(object):OUTPUT_PATH = "/XXX/video-srt/audio/" #输出文件目录APP_ID = "******" # 对应上述APPIDSECRET_ID = "******" # 对应上述SecretIdSECRET_KEY = "******" # 对应上述SecretKey
(2)使用官网提供的sdk
找到腾讯云语音识别服务下的录音文件识别的API文档,滑动到下方,找到开发者资源,这里笔者选择调用Python SDK。
可以看到录音文件识别是个异步服务,可通过CreateRecTask接口发送录音文件识别请求,之后可通过DescribeTaskStatus接口查询识别结果。
笔者项目中函数create_rec、函数query_rec_task分别对CreateRecTask接口和DescribeTaskStatus接口进行了封装。详细介绍如下:
CreateRecTask:
在请求时除需传入EngineModelType(引擎模型类型)、ChannelNum(识别声道数)、ResTextFormat(识别结果返回形式)、SourceType(语音数据来源)等这些必选参数外,还可根据需要传入FilterDirty(是否过滤脏词)、FilterModal(是否过滤语气词)等参数。
该请求成功后将返回RequestId、TaskId等信息。
def create_rec(engine_type, file_url):client = create_client(Config.SECRET_ID, Config.SECRET_KEY)req = models.CreateRecTaskRequest()params = {"ChannelNum": 1, "ResTextFormat": 2, "SourceType": 0, "ConvertNumMode": 1}req._deserialize(params)req.EngineModelType = engine_typereq.Url = file_urltry:resp = client.CreateRecTask(req)logger.info(resp)requesid = resp.RequestIdtaskid = resp.Data.TaskIdreturn requesid, taskidexcept Exception as err:logger.info(traceback.format_exc())return None, None
这里需要注意两个参数:
一是,ResTextFormat。识别结果返回形式有三种,这里笔者因在后续生成srt文件时,还根据单句识别结果的标点进行了一层分隔,所以选用了“词级别粒度的详细识别结果(包含标点、语速值)”的形式,若是不需要多一层划分,可直接选用“识别结果文本(含分段时间戳)”的形势。
二是,SourceType。语音数据来源分为两种,分别是语音 URL和语音数据(post body),笔者这里选用的是语音 URL,具体实现为,将本地音频上传到腾讯云的cos存储桶中,则语音URL为固定地址+音频文件名,即可实现调用。也可通过其他方式得到音频的url。
import subprocessdef upload_file(tmpAudio):objectName = tmpAudio.split("/")[-1]ret = subprocess.run(["coscmd", "-s", "upload", tmpAudio, objectName], shell=False)if ret.returncode != 0:print("error:", ret)
DescribeTaskStatus:
在请求时需传入TaskId。
该请求成功后将返回RequestId和识别结果。
def query_rec_task(taskid):client = create_client(Config.SECRET_ID, Config.SECRET_KEY)req = models.DescribeTaskStatusRequest()params = "{"TaskId":" + str(taskid) + "}"req.from_json_string(params)result = ""while True:try:resp = client.DescribeTaskStatus(req)resp_json = resp.to_json_string()logger.info(resp_json)resp_obj = json.loads(resp_json)if resp_obj["Data"]["StatusStr"] == "success":result = resp_obj["Data"]["ResultDetail"]breakif resp_obj["Data"]["Status"] == 3:return False, ""time.sleep(1)except TencentCloudSDKException as err:logger.info(err)return False, ""return True, result
这里笔者将根据ResultDetail的信息生成srt文件,所以函数query_rec_task的返回值为DescribeTaskStatus接口返回的data中的ResultDetail。
笔者这里生成的srt文件除了根据调用接口已自动划分的句子进行时间的标注外,当自动划分的句子的长度较长时,还会根据当前句子的标点,结合ResultDetail中的OffsetEndMs、StartMs、EndMs等信息对句子进行再一次分割,避免字幕一行展示过多的情况。
def to_srt(src_txt):flag_word = ["。", "?", "!", ","]basic_line = 15srt_txt = ""count = 1 for i in range(len(src_txt)): current_sentence = src_txt[i]["FinalSentence"] last_time = ms_to_hours(src_txt[i]["StartMs"]) len_rec = len(current_sentence) if len_rec > basic_line: start_rec = 0 last_time = ms_to_hours(src_txt[i]["StartMs"]) while(len_rec > basic_line): flag = True for j in flag_word: if j in current_sentence[start_rec:start_rec+basic_line]: loc_rec = current_sentence.index(j, start_rec, start_rec+basic_line) + 1 flag = False break if flag: loc_rec = start_rec + basic_line current_txt = current_sentence[start_rec:loc_rec] + "\n" start_time = last_time end_time = ms_to_hours(src_txt[i]["Words"][loc_rec]["OffsetEndMs"]+src_txt[i]["StartMs"]) if current_sentence[start_rec:] != "" and current_sentence[start_rec:] != None: srt_txt = srt_txt + str(count) + "\n" + start_time + "-->" + end_time + "\n" + current_txt + "\n" count += 1 start_rec = loc_rec last_time = end_time len_rec = len(current_sentence[loc_rec:]) current_txt = current_sentence[start_rec:] + "\n" start_time = last_time end_time = ms_to_hours(src_txt[i]["EndMs"]) if current_sentence[start_rec:] != "" and current_sentence[start_rec:] != None: srt_txt = srt_txt + str(count) + "\n" + start_time + "-->" + end_time + "\n" + current_txt + "\n" count += 1 else: start_time = last_time end_time = ms_to_hours(src_txt[i]["EndMs"]) srt_txt = srt_txt + str(count) + "\n" + start_time + "-->" + end_time + "\n" + current_sentence + "\n"+"\n" count += 1return srt_txt
这里srt文件最终生成的位置与Config文件中的OUTPUT_PATH相关。
(1)原视频文件的名称需与srt文件相同
(2)选择打开方式
(3)有字幕的视频
至此,给无字幕视频生成字幕已经实现,完整工程代码放在附录中,除去修改一些配置,使用起来较为简便,欢迎感兴趣的同学前来使用!
工程代码:https://github.com/ForestSkyzzx/video-srt
腾讯云智能录音文件识别:https://cloud.tencent.com/product/asr
标签:
比我国晚3小时。马尔代夫全称:马尔代夫共和国,原名马尔代夫群岛,1968年11月改为现名,位于南亚,是印...
籍贯是指出生地,严格来说是指祖籍所在地,就是你家里父辈爷爷辈的所在地。户籍地并不一定是这个人的籍...
仓储物流“成渝圈”如何乘势而上? 12月3日,连接昆明和万象的中老铁路全线开通运营,被惠及的显...
两件西周青铜簋时隔三千年成功配对 考古工作者介绍,这个铜簋的盖、身分别时隔40余年出土,纹饰...
“医保砍价”不是一个人在战斗 晁星 “我眼泪都快掉下来了”“每一个小群体都不该被放弃”…...
“购物成瘾”真的是一种病 刘艳 牛雅娟 本周日即将迎来“双十二”促销季,很多人又开始摩拳...
因迷恋山间风景,一男子在甘孜州稻城县海拔4000多米的无人区迷失方向,随后与同伴失联。12月的稻城...
嫌疑人DNA信息比中后,成都市公安局刑侦支队技术处DNA实验室民警白小刚一下坐在凳子上,恍惚迟疑间...
一批反映南京大屠杀历史的新书发布 新华社南京12月7日电(记者邱冰清、蒋芳)“以史为鉴,开创未来...
我在现场·照片背后的故事|电影《亲爱的》里面没有的结局,在我眼前“上映” 12月6日,在深圳市...
冥想?泡脚?不如听听助眠音乐 晚上睡不着,白天睡不醒,成为最贴合都市人群的“睡眠画像”。随...
养老话题 老年教育面临缺口 “终身教育”潜力无限 【现实挑战】“新老年”群体愿意在培养兴...
孙海洋被拐14年儿子如何找到的? 警方侦办另一宗拐骗儿童案时发现线索,通过人像比对、DNA确认找...
北京天文馆、圆明园将对未成年人免费开放 12月6日,北京天文馆发布通知称,12月8日起试行对未成...
今年全国粮食总产量再创新高 连续7年保持在1 3万亿斤以上 根据对全国31个省(区、市)的抽样调...
斑块软的很危险 硬的就无碍? 血管里的“垃圾”分类 赶快学起来! 一项最新研究显示:中国...
诺西那生钠注射液大幅降价 聚焦医保谈判背后脊髓性肌萎缩症家庭 医保目录公布那天 好多家长都...
抖音“窗花剪剪”遭抄袭 被判获赔20万元 法院认为“窗花剪剪”的这种表达方式理应受到《著作权...
公安机关近日侦破3起拐卖儿童案件 失散十几年 3组家庭终于团圆了 北京青年报记者12月6日从公...
2021年度十大网络用语发布 本报讯(记者 路艳霞)作为年度“汉语盘点”活动最具网络特色的组成部...
北京天文馆向未成年人免费开放 本报讯(记者 牛伟坤)北京天文馆对票价免费及优惠政策作出调整:1...
2021北京百个网红打卡地发布 本报讯(记者 李洋)2021北京网红打卡地推荐榜单昨晚正式发布。自然...