本文共享自华为云社区《运用录音文件极速版为视频生成字幕》,作者:戈兀。

引言

越来越多的人们运用抖音、B站等视频app,记录、共享日常生活,随之互联网上产生了大量的长、短视频。字幕是影响视频观看体会的重要因素。以日常共享为主的视频创作者往往没有时刻为视频制造字幕,在创作者发音不清楚的前提下,没有字幕的视频可能会让观众困惑甚至产生理解误差。而带字幕的视频让观众有更好的观看体会,“趁热打铁”顺畅地看完。

语音辨认技能(Automatic Speech Recognition)是一种将人的语音转换为文本的技能。跟着深度学习的开展,端到端语音辨认技能也取得了巨大的突破。将原始的音频数据,经过分帧、加窗、FFT等操作后,得到描绘音频在时、频域信息的梅尔特征或是Fbank特征。将特征送入transformer等神经网络,输出对应的文本信息。此外,由大量文本练习的语言模型(language model)能够纠正语音辨认输出文本不通顺的问题,改进阅读体会。而热词技能也被用来解决语音辨认的领域适配问题,如同音不同字。

本文将介绍怎么运用录音文件辨认极速版给无字幕视频自动生成字幕。

录音文件辨认极速版采用同步接口,运用GPU加快模型的推理进程。关于两个小时内的音、视频文件,能够在1分钟内回来辨认成果,满足准实时字幕、音频质检等对辨认速度有要求的场景。感兴趣的读者能够点击录音文件辨认极速版文档,了解详情。

:本文同步发布至华为云AI Gallery Notebook,能够在AI Gallery上运转:运用录音文件极速版为视频生成字幕

原理解说

给无字幕视频生成字幕,便是从视频中的提取音频流,将音频流送入录音文件辨认极速版,得到辨认文字,和对应的时刻戳信息。然后将其转换为视频字幕文件格局,如srt文件。得到srt字幕文件后,在播映视频时,载入字幕文件,就能够看到字幕了。

因而,整个流程如下:

1、运用ffmpeg东西,从视频中提取音频流

2、设置适合的参数,运用录音文件辨认极速版,催音频文件进行辨认

3、对辨认成果,包含文字和时刻戳信息,进行处理,得到视频字幕文件

4、将命名相同的视频文件与 srt 文件放在同一目录下,用播映器翻开,即可得到有字幕的视频。或者运用ffmpeg,以硬字幕的方式,将字幕嵌入到视频中。

:SRT(SubRip 文件格局)是以 SubRip 文件格局保存的简单字幕文件,扩展名为 .srt。每个字幕在 SRT 文件中有四个部分:

  1. 指示字幕编号或位置的数字计数器。
  2. 字幕的开端和完毕时刻。
  3. 一行或多行的字幕文本
  4. 表明字幕完毕的空行

代码开发

过程一:提取音频流

采用ffmpeg从视频文件中提取音频流,并保存为音频文件output.wav

ffmpeg -i input.mp4 -ar 16000 -ac 1 output.wav

-ar指定保存音频文件的采样率,这里16000表明1秒钟,保存16000个采样点数据;-ac指定保存音频的通道数,这里1表明保存为单通道音频。

过程二:装置语音辨认python SDK

在装置python3后,用pip装置其他依靠依靠包

pip install setuptools
pip install requests
pip install websocket-client

下载最新版python sdk源码:sis-sdk-repository.obs.cn-north-1.myhuaweicloud.com/python/huaw…

进入下载的Python SDK目录,在setup.py所在层目录履行 python setup.py install 命令,完成SDK装置。

过程三:调用录音文件极速版

  • 导入依靠包

    from huaweicloud_sis.client.flash_lasr_client import FlashLasrClient from huaweicloud_sis.bean.flash_lasr_request import FlashLasrRequest from huaweicloud_sis.exception.exceptions import ClientException from huaweicloud_sis.exception.exceptions import ServerException from huaweicloud_sis.bean.sis_config import SisConfig import json

  • 初始化客户端

    config = SisConfig() config.set_connect_timeout(50) config.set_read_timeout(50) client = FlashLasrClient(ak=ak, sk=sk, region=region, project_id=project_id, sis_config=config)

  • 构造恳求

    asr_request = FlashLasrRequest() asr_request.set_obs_bucket_name(obs_bucket_name) # 设置存放音频的桶名,必选 asr_request.set_obs_object_key(obs_object_key) # 设置OBS桶中的对象的键值,必选 asr_request.set_audio_format(audio_format) # 音频格局,必选 asr_request.set_property(property) # property,比如:chinese_16k_conversation asr_request.set_add_punc(‘yes’) asr_request.set_digit_norm(‘no’) asr_request.set_need_word_info(‘yes’) asr_request.set_first_channel_only(‘yes’)

为视频产生字幕文件时,不仅需求文字,也需求文字对应的时刻戳信息。当一句话过长,屏幕无法完好显现时,就需求对这句话进行切分。因而,只是根据每个语句的开始和截止时刻,无法准确的确定切分后两句话的开始和截止时刻。因而咱们需求字等级的时刻信息。而将need_word_info配置为’yes’,就能够输出字等级的时刻戳信息。如下:

"word_info": [
      {
        "start_time": 590,
        "word": "哎",
        "end_time": 630
      },
      {
        "start_time": 830,
        "word": "大",
        "end_time": 870
      },
      {
        "start_time": 950,
        "word": "家",
        "end_time": 990
      },
      {
        "start_time": 1110,
        "word": "好",
        "end_time": 1150
      },
]
  • 接下里发送辨认恳求

    result = client.get_flash_lasr_result(asr_request)

  • 拿到带有具体时刻戳信息的辨认成果result:

    “result”: { “score”: 0.9358551502227783, “word_info”: [ { “start_time”: 590, “word”: “哎”, “end_time”: 630 }, { “start_time”: 830, “word”: “大”, “end_time”: 870 }, { “start_time”: 950, “word”: “家”, “end_time”: 990 }, { “start_time”: 1110, “word”: “好”, “end_time”: 1150 }, { “start_time”: 1750, “word”: “我”, “end_time”: 1790 }, { “start_time”: 1910, “word”: “是”, “end_time”: 1950 }, { “start_time”: 2070, “word”: “你”, “end_time”: 2110 }, { “start_time”: 2190, “word”: “们”, “end_time”: 2230 }, { “start_time”: 2350, “word”: “的”, “end_time”: 2390 }, { “start_time”: 2870, “word”: “音”, “end_time”: 2910 }, { “start_time”: 3030, “word”: “乐”, “end_time”: 3070 }, { “start_time”: 3190, “word”: “老”, “end_time”: 3230 }, { “start_time”: 3350, “word”: “师”, “end_time”: 3390 }, { “start_time”: 3590, “word”: “康”, “end_time”: 3630 }, { “start_time”: 3750, “word”: “老”, “end_time”: 3790 }, { “start_time”: 3950, “word”: “师”, “end_time”: 3990 }, { “start_time”: 4830, “word”: “那”, “end_time”: 4870 }, { “start_time”: 4990, “word”: “么”, “end_time”: 5030 }, { “start_time”: 5350, “word”: “这”, “end_time”: 5390 }, { “start_time”: 5550, “word”: “几”, “end_time”: 5590 }, { “start_time”: 5750, “word”: “系”, “end_time”: 5790 }, { “start_time”: 5870, “word”: “列”, “end_time”: 5910 }, { “start_time”: 6070, “word”: “呢”, “end_time”: 6110 }, { “start_time”: 6310, “word”: “我”, “end_time”: 6350 }, { “start_time”: 6390, “word”: “们”, “end_time”: 6470 }, { “start_time”: 6510, “word”: “来”, “end_time”: 6550 }, { “start_time”: 6670, “word”: “到”, “end_time”: 6710 }, { “start_time”: 6830, “word”: “了”, “end_time”: 6870 }, { “start_time”: 7430, “word”: “发”, “end_time”: 7470 }, { “start_time”: 7630, “word”: “声”, “end_time”: 7670 }, { “start_time”: 7830, “word”: “练”, “end_time”: 7870 }, { “start_time”: 8030, “word”: “习”, “end_time”: 8070 }, { “start_time”: 8950, “word”: “三”, “end_time”: 8990 }, { “start_time”: 9190, “word”: “十”, “end_time”: 9230 }, { “start_time”: 9350, “word”: “五”, “end_time”: 9390 }, { “start_time”: 9470, “word”: “讲”, “end_time”: 9510 } ], “text”: “哎,大家好,我是你们的音乐教师康教师。那么这几系列呢,咱们来到了发声练习三十五讲。” }, “start_time”: 510, “end_time”: 9640 }

过程四:将辨认成果转为srt字幕格局文件

因为视频播映界面的宽度有限,当一句话包含的文字数过多时,会存在一行放不下的问题。因而咱们在生成srt文件时,需求将文字数量过长的一句话切分为两句话,分别在不同的时刻段显现。企切分后的榜首句话的开始时刻不变,截止时刻为最终一个字的截止时刻;第二句话的开始时刻为榜首个字的开始时刻,截止时刻不变。这样就确保切分后两句话的时刻戳也是正确的,进而在适宜的视频帧中显现正确的文本内容。

def json2srt(json_result):
    results = ""
    count = 1
    max_word_in_line = 15
    min_word_in_line = 3
    punc = ["。", "?", "!", ","]
    segments = json_result['flash_result'][0]['sentences']
    for i in range(len(segments)):
        current_result = segments[i]
        current_sentence = current_result["result"]["text"]
        if len(current_result["result"]["word_info"]) > max_word_in_line:
            srt_result = ""
            srt_result_len = 0
            current_segment = ""
            cnt = 0
            start = True
            for i in range(len(current_sentence)):
                if current_sentence[i] not in punc:
                    if start:
                        start_time = current_result["result"]["word_info"][cnt]['start_time']
                        start = False
                    else:
                        end_time = current_result["result"]["word_info"][cnt]['end_time']
                    current_segment += current_sentence[i]
                    srt_result_len += 1
                    cnt += 1
                else:
                    if srt_result_len < min_word_in_line:
                        srt_result += current_segment + current_sentence[i]
                        current_segment = ""
                    else:
                        srt_result += current_segment + current_sentence[i]
                        current_segment = ""
                        start_time = time_format(start_time)
                        end_time = time_format(end_time)
                        if srt_result[-1] == ",":
                            srt_result = srt_result[:-1]
                        results += str(count) + "\n" + start_time + "-->" + end_time + "\n" + srt_result + "\n" + "\n"
                        count += 1
                        start = True
                        srt_result = ""
        else:
            start_time = time_format(current_result["start_time"])
            end_time = time_format(current_result["end_time"])
            if current_sentence[-1] == ",":
                current_sentence = current_sentence[:-1]
            results += str(count) + "\n" + start_time + "-->" + end_time + "\n" + current_sentence + "\n" + "\n"
            count += 1
    return results

得到srt格局的字幕文件

教你1分钟搞定2小时字幕

过程五:播映视频,载入字幕

修正文件名,确保srt文件和原始视频文件命名相同,然后用暴风影音播映视频:

过程六:运用ffmpeg给视频增加硬字幕(可选)

ffmpeg -i input.mp4 -vf subtitles=subtitle.srt output_srt.mp4

注: 硬字幕是将字幕烘托到视频的纹理上,然后将其编码成独立于视频格局的一个完好视频。硬字幕与视频是一个整体,不能更改或删去。

点击重视,榜首时刻了解华为云新鲜技能~