見出し画像

DavinciResolveAPIでタイムラインに配置したText+からテキストを取得する方法

今回の記事もDavinci Resolve API のText+についてです。
2022/3/12に問題点を追記、3/15に対策内容を更新

前回はタイムラインにText+を配置、表示テキストを設定する方法を記載しました。(前回:https://note.com/hitsugi_yukana/n/n1601e81df8d7
今回はタイムラインに配置済みのText+から表示テキストを取得する方法についてまとめました。

前回同様、コードに変なところがあってもご容赦を。

基本的な考え方

スクリプト例

resolve = Resolve()		--Rosolveオブジェクト取得
projectManager = resolve:GetProjectManager()	--プロジェクトマネージャー取得
project = projectManager:GetCurrentProject()	--現在読み込まれているDaVinci Resolveプロジェクト取得 
timeline = project:GetCurrentTimeline()    --現在のタイムライン取得
 
for k,v in pairs(tl:GetItemsInTrack("video", 1)) do
    if v:GetName() == "Text+" then    -- 動画ファイルなどが混在する可能性があるのでクリップ名で条件分岐
        toolList = v:GetFusionCompByIndex(1):GetToolList()    -- Fusionに設定されたツール一覧取得(1番目にText+、2番目にMediaOut)

        textframe = toolList[1].StyledText:GetKeyFrames()     -- Text+に設定されたテキストのキーフレーム一覧取得
        dump(toolList[1].StyledText:GetKeyFrames())

        -- 設定済みキーフレームを指定してテキストを取得する(今回は0, 10, 50, 100フレームに設定済み)
        -- 未設定キーフレームを指定した場合、その直前の設定済みキーフレームを参照する。
        -- それもないなら直後の設定済みキーフレームを参照する。
        --  (10, 50フレームにテキストを設定済みで、40フレームを指定した場合、直前の10フレームのテキストを参照する)
        --  (10, 50フレームにテキストを設定済みで、5フレームを指定した場合、一番早い10フレームのテキストを参照する)
        print(toolList[1].StyledText[0])    
        print(toolList[1].StyledText[20])  -- 20フレームに設定がないので、直前の10フレームの設定値が参照される
        print(toolList[1].StyledText[50])
        print(toolList[1].StyledText[100])
        
        -- 設定済みキーフレームのテキストを順番に表示する
        for k2=1, #textframe do
	    print("[" .. k2 .. "]" .. toolList[1].StyledText[textframe[k2]])		-- Text+に設定されたキーフレームのテキストを表示
        end
    end
end
 
--[[
出力される内容
table: 0x02a13a68
	1 = 0
	2 = 10
	3 = 50
	4 = 100
Frame 0
Frame 0
Frame 50
Frame 100
[1]Frame 0
[2]Frame 10
[3]Frame 50
[4]Frame 100
--]]
実行例のタイムライン:Text+一つだけ


簡単な説明

  1. Timeline:GetItemInTrack("video", ch)でビデオトラックのタイムラインに配置されたクリップ一覧取得  (chは取得したいトラック番号)

  2. if TimelineItem:GetName() == "Text+" then ~ end でText+のみ処理対象にする

  3. TimelineItem:GetFusionCompByIndex(1):GetToolList()でText+のツールリスト取得(必要なのはインデックス番号1番)

  4. ToolList[1].StyledText:GetKeyFrames()で設定済みキーフレームの一覧を取得

  5. for文で設定済みキーフレーム一覧を順次参照する

Text+に設定されたテキストを順番に参照するなら一度StyledText:GetKeyFrames()で設定済みキーフレーム一覧を取得して、それを元にStyledText[keyframe]でテキスト取得する、という手順が基本になると思います。

ちなみにタイムラインに配置されたText+クリップをトリムしたり再生時間を変更しても、設定されたキーフレームは特に変化しないようです。
例えば10秒間のText+クリップに対して、11秒あたりにテキストを設定することも可能ですし、0~5秒部分を切り取ってもその部分のテキストと再生タイミング(キーフレーム)は保持したままです。

この辺はタイムライン1に配置されたタイムライン2の一部を切り取っても、タイムライン2に配置された動画そのものは全く影響を受けないのと似てます。
Text+クリップの長さを変えたりすると再生タイミングがズレる可能性があるので、その点は注意が必要そうです。



BezierSplineクラスを設定した場合の注意点

(2022/3/12追記分)

DavinciResolve再起動後にStyledTextが参照できない問題

記事投稿後に上記のやり方でテキストを取得しようとしたところ、上手くいかない場合が生じました。
どうもText+を配置した後は特に問題ないのですが、DavinciResolveを再起動するとStyledTextがnilになっている模様

一体どういうことかと思って調べてみると、StyledTextにBezierSplineクラスを設定することによってToolListの並び順に影響があるようです。

まず、タイムラインへText+配置した直後のToolListを確認してみます。
clipは先述のコードのtl:GetItemsInTrack("video", 1)で取得したText+クリップとして読んでください。


local comp = clip:GetFusionCompByIndex(1)    -- Fusionコンポジション取得
local toollist = comp:GetToolList()	--ツールリスト取得
dump(toollist)

出力すると以下の通り、Text+ノードとMediaoutノードがあります。

次に、Text+ノードのStyledTextにBezierSplineクラスを設定します。
ちなみにこれはテキスト欄の横の◆が赤くなっているのと同じ状態です。
(キーフレームごとに表示内容などを設定している状態)

StyledTextにBezierSpline設定済みの状態

この状態で出力すると、ToolListにBezierSplineノードが追加されています。
BezierSplineってText+の一部として管理されるわけではなく、別ノードとして同列に管理されるんですね。
これは予想していませんでした。

ここまでならText+ノードがToolListの一番最初にあるので特に問題はありません。
toollist[1].StyledText[keyframe]でテキスト内容を参照できます。

しかし、DavinciResolveを再起動後にToolListを再度確認すると、ToolList内がソートされてBezierSplineノードが一番最初に来ます。

再起動前はtoollist[1]がText+ノードなのでテキスト内容を参照できていましたが、再起動後はtoollist[1]がBezierSplineノードになるのでエラーが発生します。

対策方法

再起動によって並び順が変わるのはどうにも釈然としませんが、ともあれ原因はわかりました。
次は対策です。

並び順が変わるのであればText+ノードを検索して返却すればOKですね。
Resolve():GetHelp()で調べてみると、各ノードはNameプロパティとClassNameプロパティを持っているようです。

Nameプロパティは文字通りノードに付けた名前。(画像ではText+ノード名が"Template")
ClassNameプロパティはノードの種類です。Text+の場合は"TextPlus"、BezierSplineノードなら"BezierSpline"です。

ClassNameプロパティ、Nameプロパティを確認

ちなみにStyledTextに設定したBezierSplineノードの名前は”Text+ノード名"に"StyledText"を追加したものとなるようです。
(画像ではBezierSplineノード名は"TemplateStyledText")

FontやSizeなどにBezierSplineを設定した場合は"TemplateFont"とか"TemplateSize"みたいな名前のノードが追加されるのでしょう。おそらく。試してないのでわかりませんが。

判別方法はわかりましたので、今回はクリップ内にText+ノードが一つしかないことを利用して、ClassNameプロパティで判別しましょう。

for文でノードを順番に参照して確認するのも良いのですが、Compsition:GetToolList()は第2引数で取得するノード属性(ClassName)を限定できるので、そちらでText+ノードのみを取得します。(https://documents.blackmagicdesign.com/UserManuals/Fusion8_Scripting_Guide.pdf の78P参照)

Compsition:GetToolList(bool selected, string type = nil)
 
-- (bool)selected : 選択状態。おそらくFusion画面で動かすスクリプトを想定していると思われる。
--                  省略するとfalseになる。
--                  true  選択したノードのみを返り値とする?
--                  false 指定したFusionコンポジション内のノード全てを返り値(配列)とする。
--                  Edit画面、Cut画面で動かすスクリプトの場合、そもそもノード選択しないので基本的にfalseで良い?
-- (string) type  : 取得対象となるノード属性。
--                  省略するかnilが渡すと全ノードを対象とする。
 
-- 例(Text+ノードを全て取得する場合)
comp:GetToolList(false, "TextPlus")

対策スクリプト例

local comp = clip:GetFusionCompByIndex(1)   -- Fusionコンポジション取得
local toollist = comp:GetToolList(false, "TextPlus")	--ツールリスト取得(Text+ノードのみ)
dump(toollist)
print("StyledText[0] : " .. toollist[i].StyledText[1])

出力結果は以下の通り。StyledTextの0フレーム目のテキストを出力できました。

もしTextPlusノードが複数あるならfor文でノードを順番に参照し、Nameプロパティで判別すれば良いでしょう。
その場合は判別できるようなノード名をあらかじめ決めておく必要があります。


対策まとめ

まず原因。BezierSplineを設定するとText+を参照できなくなる現象について。

  1. Text+.StyledTextにBezierSplineを設定すると、該当BezierSplineはToolListに追加される。

  2. DavinciResolveを再起動するとToolList内のノードが並び替えられる。

  3. 再起動時のToolList並び替えに寄ってBezierSplineノードはText+ノードより上位に来る。

  4. Text+ノードのインデックス番号が1→2にズレる。(BezierSplineを設定する項目が増えればもっとズレる)

  5. ToolList[1]というようにインデックス番号で参照していると、参照ノードがText+ノードからBezierSplineノードへと変わってしまう。

次に対策。Text+などの目的のノードの見つけ方。

  1. 各ノードはClassNameプロパティ、Nameプロパティを持つ。

  2. 探したい種類のノードが1つだけならClassNameプロパティで判別する。

  3. 探したい種類のノードが複数個あるならNameプロパティで判別する。

  4. ClassNameで判別するならComposition:GetToolList(false, ClassName)で対象ノードを限定するか、for文で回しつつNameプロパティで判別し、目的のノードが見つかったらそれを返す



こんな感じでしょうか。
まさか再起動でノードの並び順が変わるだなんて予想していませんでした。
原因調査と解決方法のまとめで丸一日潰れてしまい、ツール開発にまた遅れが……。

こういう情報をもっと簡単に調べられたら良いのですけれどね。
見つからないから書いているのですが。

サポートしていただけるとその分の価値を提供できてるんだなって励みになります。