tshohe's memo

おぼえたことをかく

Cloudinary で字幕を重ねた動画を取得するまでのメモ

Cloudinary で動画に字幕を重ねて表示するのを試してみたのでそのメモ。
字幕の表示自体は特定のフォーマットの字幕ファイルをアップロードしてURLで指定するだけなので簡単ですが、字幕ファイルの生成で手間取りました。

Google AI Video Transcription Add-on

Google AI Video Transcription Add-on | Cloudinary

動画を上げるときに字幕ファイルも生成して一緒に上げるAdd-onがあるのでまずそれを試してみました。 ※ Freeプランだと120 Unit (処理15秒につき1 Unit) までという制限付き

Pythonの場合はcloudinaryをpipでインストール。

pip install cloudinary

Dashboardで見える諸々の値を環境変数として読み込むようにしておきます。

import os
import cloudinary.uploader

video_file = 'douga.mp4'

cloudinary.config(
  cloud_name = os.environ['CLOUDINARY_CLOUD_NAME'],
  api_key = os.environ['CLOUDINARY_API_KEY'],
  api_secret = os.environ['CLOUDINARY_SECRET']
)

cloudinary.uploader.upload(video_file,
  resource_type = "video", 
  raw_convert = "google_speech:srt:ja-JP")

と、上のコード一応エラーなく実行され、動画ファイルと字幕ファイルがCloudinaryにアップロードされることはされます。しかし、字幕ファイルが空でダウンロードしようとしてもGenerate Errorと表示されてしまい使い物にならず……。

内部的に使っているGoogle Speech to Textが何も検出できなかった場合に空のレスポンスを返すのでそのせいなのかも知れませんが、詳しくは調べられておらず。ffmpegで細かい調整をしていけば検出されそうな気もします。

Google Speech to Text

結局普通にGoogle Speech to Textで変換して字幕ファイルを作成しました。

ffmpegでmp4からflacに変換します。
ffmpegが入っていない場合はpipとかで入れておく

# acodec: codec
# ac: 1 -> monoral
# ar: sampling rate
# 
ffmpeg -i douga.mp4 -acodec flac -f flac -ac 1 -y -ar 16000 -filter:a "volume=35dB" output.flac

音量によって検出されないこともあったので、小さい場合は少し上げてやると良さそうです。

flacからGoogle Speech-to-text APIを使って srt を生成するコードは下記の通り。(Google Speech to Textのサンプルコードのまんま)

import io
import os
import math
import output_srt

# Imports the Google Cloud client library
from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types

# Instantiates a client
client = speech.SpeechClient()

# The name of the audio file to transcribe
file_name = os.path.join(
    os.path.dirname(__file__),
    'output.flac')

# Loads the audio into memory
with io.open(file_name, 'rb') as audio_file:
    content = audio_file.read()
    audio = types.RecognitionAudio(content=content)

config = types.RecognitionConfig(
    sample_rate_hertz=16000,
    language_code='ja-JP',
    enable_word_time_offsets=True)

# Detects speech in the audio file
response = client.recognize(config, audio)
output_srt.format_transcript(response.results, file_name)

APIのレスポンスからsrtを生成するための処理(上記 ouput_srt.format_transcript 関数)については、この方のコードが参考になったので使わせてもらいました。

google-speech-to-text/format_response.py at master · Naki21/google-speech-to-text · GitHub

なんとか字幕は出たのですが短すぎてこんなのしか出ません……。
もっと文章っぽい言葉なら精度が上がるとは思うんですが、サンプルが一言だけの動画なのがよろしくなさそう。そもそもこの音声は数年前にWatson Text to Speechで生成したものなので無駄極まりないですが。

1
0:00:01,000 --> 0:00:02,700
マウスコンピューター

色々音量とかをいじると候補が変わったりはするのですが、文章らしい文章にはならなかったので手動で変更します。これまでの作業は一体...。

1
0:00:01,000 --> 0:00:02,700
マウス、コンピューターマウスが見えます

なんやかんやで作成したsrtファイルをCloudinaryにアップロードします。

そして動画のURLを https://res.cloudinary.com/<CloudName>/video/upload/l_subtitles:<字幕ファイル名>/douga.mp4 のようにすると字幕を重ねた動画を取得することが出来ました。めでたしめでたし。

f:id:tshohe:20191014002620p:plain https://res.cloudinary.com/tsts/video/upload/l_subtitles:berikoma_speak_jimaku.srt/berikoma_speak.mp4

参考にしたサイト

Cloudinaryを使って動画に字幕をつけてみた | DevelopersIO