1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

vtt から exo へ!Python の黒魔術で AviUtl を制覇せよ! (YouTube や Whisper などから得られる *.vtt 字幕ファイルを AviUtl でインポートできる *.exo オブジェクトファイルに変換する)

Posted at

vtt ファイルexo ファイルに変換して AviUtl へのインポートを試した際のメモです。(タイトルの前半部分は ChatGPT で生成しました)

コード

Google Colab で以下のコードを実行することで変換できました。

import webvtt
from datetime import datetime, timedelta

def frames_from_timestamp(timestamp_str):
    timestamp = datetime.strptime(timestamp_str, "%H:%M:%S.%f") - datetime(1900, 1, 1)
    seconds = timestamp.total_seconds()
    return int(seconds * 60)  # Convert to frames

def convert_vtt_to_exo(vtt_file, exo_file):
    vtt = webvtt.read(vtt_file)

    with open(exo_file, 'w', encoding='shift_jis', newline='\r\n') as file:
        file.write("[exedit]\nwidth=1920\nheight=1080\nrate=60\nscale=1\nlength={}\naudio_rate=44100\naudio_ch=2\n".format(frames_from_timestamp(vtt[-1].end)))

        for i, caption in enumerate(vtt):
            start_frame = frames_from_timestamp(str(caption.start))
            end_frame = frames_from_timestamp(str(caption.end))

            if i > 0:
                start_frame += 1

            if i < len(vtt) - 1:
                end_frame -= 1

            text = caption.text.encode('utf-16le').hex().ljust(4096, '0')
            file.write("[{0}]\nstart={1}\nend={2}\nlayer=9\noverlay=1\ncamera=0\n[{0}.0]\n_name=テキスト\nサイズ=100\n表示速度=0.0\n文字毎に個別オブジェクト=0\n移動座標上に表示する=0\n自動スクロール=0\nB=0\nI=0\ntype=4\nautoadjust=0\nsoft=1\nmonospace=0\nalign=4\nspacing_x=0\nspacing_y=0\nprecision=1\ncolor=0000ff\ncolor2=ffffff\nfont=メイリオ\ntext={3}\n[{0}.1]\n_name=標準描画\nX=150.0\nY=250.0\nZ=0.0\n拡大率=100.00\n透明度=0.0\n回転=0.00\nblend=0\n".format(i, start_frame, end_frame, text))

convert_vtt_to_exo('input.vtt', 'output.exo')

Google Colab

以下の notebook を動かすことで変換を試せます。

vtt2exo.ipynb

コード生成に利用したプロンプト

今回、プロンプトだけでコードを生成しようと試行錯誤しました。
上記のコードは以下のプロンプトを OpenAI に投げて生成しています。

字幕ファイル vtt ファイルを、aviutl でインポートできる exo フォーマットに変換する Python コードを書いてください。
aviutl の exoフォーマットは以下のような形式で、ファイルの文字コードは Shift_JIS です。
改行コードは LF でなくて、CR + LF です。
vtt ファイルのパースには webvtt モジュールを利用してください。


[{数字}]
start={開始フレーム}
end={停止フレーム}
layer=9
overlay=1
camera=0
[{数字}.0]
_name=テキスト
サイズ=100
表示速度=0.0
文字毎に個別オブジェクト=0
移動座標上に表示する=0
自動スクロール=0
B=0
I=0
type=4
autoadjust=0
soft=1
monospace=0
align=4
spacing_x=0
spacing_y=0
precision=1
color=0000ff
color2=ffffff
font=メイリオ
text={テキスト}
[{数字}.1]
_name=標準描画
X=150.0
Y=250.0
Z=0.0
拡大率=100.00
透明度=0.0
回転=0.00
blend=0


上記のうち、{数字} は字幕ごとに 0 始まりで順に増えていき、{開始フレーム} {停止フレーム} は1秒を60フレーム換算した、整数になります。
{開始フレーム} と {停止フレーム} は前後の要素で重複しないように指定する必要があります。
プログラム側でこの問題を防ぐために、各キャプションのフレームを調整し、
前のキャプションの終了フレームと次のキャプションの開始フレームが重複しないようにしてください。
{テキスト} は字幕の内容がはいります。文字列を utf-16le でエンコードして、16進数にした文字列にしたものを入れる必要がます。
4096 バイトの固定長で、満たない部分は 0 埋めされます。以下のようなコードになります。

text.encode('utf-16le').hex().ljust(4096, '0')

また、exo ファイルの冒頭は以下のようなヘッダーパートがあります。


[exedit]
width=1920
height=1080
rate=60
scale=1
length={最後の停止フレーム}
audio_rate=44100
audio_ch=2


{最後の停止フレーム} には、最も長い停止フレームの数が入ります。

プロンプトの改善と、コード出力

プロンプトを見てわかるとおり、最初に全ての条件を洗い出せたわけではありません。簡素な文で投げたあと、動くのに必要な条件を付け足すことで動くコードが出力されるように修正しています(フレームの重複部分や、改行コードの指定など)。文字コードの変換部分などは、言葉で説明するのが面倒なため、コードをそのまま指示してしまっています。

更に、これを実行しても直接冒頭の出力コードになったわけではなく、いくつか動かないコードを経由しています。例えば、frames_from_timestamp 関数は最初の出力では

def frames_from_timestamp(timestamp):
    seconds = timestamp.total_seconds()
    return int(seconds * 60)  # Convert to frames

となっていて、total_seconds などという属性はないためエラーになります。これを、

AttributeError: 'str' object has no attribute 'total_seconds'

というエラーがでます

というプロンプトを入力することで、

申し訳ありません、私の誤りです。
webvttモジュールでは、`caption.start`と`caption.end`は文字列として返されます。
そのため、これらの値をフレームに変換するためには、まず時間に変換する必要があります。
以下に修正したコードを提供します。
~~~

修正してくれます。

コードを動かす→エラーをフィードバック、を何回か繰り返し、最終的に動くコードを出力してくれました。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?