腾讯云语音识别使用录音文件识别实现视频自动生成字幕_AI解决方案_同尘科技
近些年,短视频、直播等线上娱乐方式快速发展,直接拉动了旅游、电商、影视创作等行业新风潮;而要呈现出一段好的视频效果,不仅考验好的拍摄技法,后期处理也是重中之重。以视频字幕为例,有字幕的视频总能“一气呵成”顺畅地看完,而无字幕总令人觉得缺失了一种味道。纯手工添加字幕,也费时费力。面对较大时长与批量化字幕处理的,多少有些苦不堪言。
本文将介绍如何借助录音文件识别服务给无字幕视频自动生成字幕。
分析调研
给无字幕视频自动生成字幕,其实就是先对视频文件导出的音频文件进行识别,得到识别文字,再通过对文字进行时间信息处理,得到视频 srt 字幕文件,在视频文件中导入 srt 字幕文件即可得到效果。实现思路如下:1. 借助 ffmpeg 从视频中提取音频。2. 调用录音文件识别服务,对音频文件进行识别。3. 对识别得到的文字与短句的时间信息进行处理得到视频 srt 字幕文件。4. 将命名相同的视频文件与 srt 文件放在同一目录下,用暴风影音或其他播放器打开,即可得到有字幕的视频。
代码开发
步骤一:借助 ffmpeg 从视频中提取音频
项目使用了 ffmpeg 依赖,需先下载安装,并设置环境变量。之后就可通过引入 subprocess 库,执行 ffmpeg 命令,启动一个新进程,完成对音频的提取。
import subprocessdef extract_audio(video, tmpAudio): ret = subprocess.run('ffmpeg -version', shell=True) if ret.returncode != 0: print("请先安装 ffmpeg 依赖 ,并设置环境变量") return ret = subprocess.check_call(['ffmpeg', '-i', video, '-vn', '-ar', "16000", tmpAudio], shell=False) if ret.returncode != 0: print("error:", ret)
步骤二:识别音频文件
这里选择的录音文件识别服务是腾讯云 ASR 的录音文件识别,录音文件识别可以在调用时直接根据语句之间的停顿智能断句、添加标点符号,无需再调用其他接口进行语句拆分,同时返回结果数据也可根据不同需求进行多种选择,如是否过滤脏词、是否过滤语气词等。录音文件识别接口详情请参见 录音文件识别请求。1. 访问腾讯云的服务,需要使用 API 密钥(SecertId 与 SecretKey),可在 API 密钥管理 页面新建与查询,稍后配置到 config 文件中即可。
本项目配置在 tencent/config.py 当中。
class Config(object): OUTPUT_PATH = '/XXX/video-srt/audio/' #输出文件目录 APP_ID = '******' # 对应上述APPID SECRET_ID = '******' # 对应上述SecretId SECRET_KEY = '******' # 对应上述SecretKey
2. 使用官网提供的 SDK
获取腾讯云语音识别服务提供的 SDK,详情请参见录音文件识别请求 > 开发者资源,本项目调用 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_type req.Url = file_url try: resp = client.CreateRecTask(req) logger.info(resp) requesid = resp.RequestId taskid = resp.Data.TaskId return requesid, taskid except 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"] break if 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 字幕文件
生成的 srt 文件除了根据调用接口已自动划分的句子进行时间的标注外,当自动划分的句子的长度较长时,还会根据当前句子的标点,结合 ResultDetail 中的 OffsetEndMs、StartMs、EndMs 等信息对句子进行再一次分割,避免字幕一行展示过多的情况。
def to_srt(src_txt): flag_word = ["。", "?", "!", ","] basic_line = 15 srt_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 += 1 return srt_txt
srt 文件最终生成的位置与 Config 文件中的 OUTPUT_PATH 相关。
步骤四:得到有字幕的视频
1. 原视频文件的名称需与 srt 文件相同。
2. 选择打开方式。
3. 有字幕的视频。
至此,给无字幕视频生成字幕已经实现,完整工程代码放在附录中,除去修改一些配置,使用起来较为简便。
附录
工程代码:地址
对解决方案有疑惑?想了解解决方案收费? 联系解决方案专家
腾讯云限时活动1折起,即将结束: 马上收藏
同尘科技为腾讯云授权服务中心,购买腾讯云享受折上折,更有现金返利:同意关联,立享优惠
阿里云解决方案也看看?: 点击对比阿里云的解决方案
暂无评论,你要说点什么吗?