はじまり
ぐぬぬ〜・・・悔しい〜・・・
どうしたんだい? 悔しいのかい?
ああ、さっき試していたDaVinci Resolve編集の効率化ツールが、
役に立たなそうなことが分かって、開発を断念したのだよ・・・
この悔しさを記事にぶつけるぜえ〜・・・!
よーし、行ってみよう!
効率化のツールの概要
まず、ゆっくり動画のテンプレを作ります。
テンプレの構成は以下の感じです。
①左下と右下にキャラクターの画像を配置して、
②キャラクターの音声を再生すると同時に、
③キャラクターの画像および字幕を切り替えます。
このテンプレで、①は制作者がそのフレームの状況を鑑みて画像を選択すれば良いのですが、
②と③に関しては、どこでその音声を流して、字幕を表示させるかどうかは一意に決まっています。
そのため、②で音声ファイル(.wavファイル)を設置する処理を、
③でテキストを自動で設置してその内容を自動入力する試みを、今回行いました。
試したこと
今回、自動化を試みた環境は以下のとおりです。
- DaVinci Resolve 18(DaVinci Resolve Studio 18 ではない。)
- macOS Monterey
- Python3
DaVinci ResolveでのPythonの実行方法
まず、DaVinci Resolve Studio 18ではないので、外部ファイルからのResolve向けのスクリプトの実行ができません。そのため、DaVinci Resolve画面上のConsoleからPythonを実行します。
ConsoleからPy3を選んだときに「Python not found」的なメッセージが出たら、Python3をここからインストールします。(僕は既にanacondaが入っているときにその「Python not found」的なメッセージ食らったのですが、Resolveがどの環境変数を読み取っているのかよく分からなかったので、渋々新しくPythonをインストールしました。)
そして、Python3がResolve上で使えるようになったら早速スクリプトを組んでいきます。
参考にした資料は、以下になります。
音声メディアをインポートする。
まず、②のwavファイルをタイムラインに配置する自動化を試しました。
Console上では、resolve = GetResolve()
は記述する必要はなく、既にresolve
はクラスとして使える状態になっています。
そして、以下のような記述をして、1つのフォルダに格納されている音声メディア達をメディアプールに入れます。
project_manager = resolve.GetProjectManager()
current_project = project_manager.GetCurrentProject(
voice_path = "/Users/hogehoge/Downloads/20220912_ghostoftsushima_02/voices"
media_storage = resolve.GetMediaStorage()
clips_added = media_storage.AddItemListToMediaPool(voice_path)
そして、そのメディアプールに入れた音声メディアをタイムライン上にマーカーで印を付けたところにインポート出来ないかどうかを試しました。
すると、マーカーの取得自体は可能で、返り値のdict型オブジェクトのキーが、frame値になっているので、そのframeをタイムコードに変換してあげれば、音声ファイルの配置箇所の指定は可能そうです。
current_timeline = current_project.GetCurrentTimeline()
markers = current_timeline.GetMarkers()
次に、音声メディアを指定した場所に配置することが出来るかどうかを試してみました。
結論から言うと、この部分が出来なさそうでした・・・
以下のようなスクリプトを実行してみましたが、なぜか音声メディアを既にタイムライン上にある最後のメディアの直後に置いてしまうようで、これだとあまり効率化にはなりません・・・
def FRAME_VALUE(time_unit : str) -> int:
if type(time_unit) != str:
raise TypeError("time_unit must be str.")
return_value = 0
FRAME_OF_SEC = 30
FRAME_OF_MINUTE = FRAME_OF_SEC * 60
FRAME_OF_HOUR = FRAME_OF_MINUTE * 60
if time_unit == "sec":
return_value = FRAME_OF_SEC
elif time_unit == "minute":
return_value = FRAME_OF_MINUTE
elif time_unit == "hour":
return_value = FRAME_OF_HOUR
else:
raise ValueError("time_unit must be 'sec', 'minute' or 'hour'.")
return return_value
def timecode_to_frame(timecode : str, start_frame : int = 0) -> int:
COLON = ":"
if type(timecode) != str:
raise TypeError("timecode must be str.")
if type(start_frame) != int:
raise TypeError("start_frame must be int.")
if COLON not in timecode:
raise TypeError("timecode must contain colon.")
time_list = timecode.split(COLON)
if len(time_list) != 4:
raise TypeError("timecode must be \"hour : minute : second : frame\".")
frame = sum([int(time_list[0]) * FRAME_VALUE("hour")
, int(time_list[1]) * FRAME_VALUE("minute")
, int(time_list[2]) * FRAME_VALUE("sec")
, int(time_list[3])
])
frame = frame + start_frame
return frame
for i in range(0, len(clips_added), 1):
tmp_duration = clips_added[i].GetClipProperty()["Duration"]
if i == 0:
current_timeline.SetCurrentTimecode('01:18:29:13')
if i == 1:
current_timeline.SetCurrentTimecode('01:18:33:13')
start_frame = 1000
end_frame = start_frame + timecode_to_frame(tmp_duration)
print_log(tmp_duration)
print_log(end_frame)
media_pool.AppendToTimeline([{
"mediaPoolItem": clips_added[i]
, "startFrame": start_frame
, "endFrame": end_frame
}])
AppendToTimeline()
関数は、引数に開始フレーム位置および開始タイムコードを取りません。
Wiki上では、"startFrame"
と記述がありますが、これは「メディア内の」開始フレーム位置なので、タイムライン上の開始フレーム位置を指定することは、この関数上では出来ません。
そのため、SetCurrentTimecode()
関数で開始タイムコードが指定できるのかと思い試しましたが、どうやら違うようです。(右下の方に音声メディアが配置できるかなあ?)
既にタイムライン上にある最後のメディアの直後に置いてしまっています・・・失敗・・・(右下ではなく、その左の方に置かれてしまっている。)
以上を試して、他にタイムライン上に音声メディアを指定した位置に配置する術が他に見つからず、断念しました・・・
(ImportIntoTimeline()
という関数もあるのですが、この関数はどうやらAAF拡張子のファイルのみが対象になるようで、wavファイルを使って実行したところ、何も配置されませんでした。)
テキストをタイムラインに配置する。
③のテキストの配置の自動化ですが、こちらは試しませんでした!
②が出来ないと分かった時点で、効率化の美味みが半分くらい消失していましたし、テキストも音声メディアと同じ理由で配置する場所を指定できるかどうかが疑わしかったため、調査も行っていません。
テキストのプロパティを変える手段としては、以下のような記述になるかと思います。
SetProperty()で編集できるプロパティは、こちらに載っていたので試してみたい方はご参考までに。
timeline_items = current_timeline.GetItemListInTrack("video", 1)
timeline_items[0].SetProperty('ZoomX', 2.0)
おしまい
くっそ〜、DaVinciだから簡単に動くと思ったんだがな〜
まあ、そういうこともあるよねえ。
今回は、スクリプトが上手くいかなかったというだけであって、Resolve上でゆっくり動画っぽいものを制作することは問題なく出来ます。以下のような感じで。
以上になります!
コメント