見出し画像

【DaVinci Resolve API】クリップを好きなタイミングに配置する方法

まえがき

こんにちは。火注ゆかなです。
今回の記事はタイトルの通り、クリップを任意の再生時間(タイミング)に配置する方法です。

今まで投稿してきた内容と違い、APIドキュメント(https://gist.github.com/X-Raym/2f2bf453fc481b9cca624d7ca0e19de8)を読んでいれば該当するメソッドは見つかります。MediaPoolオブジェクトのAppendToTimelineメソッドですね。クリップをタイムラインへ配置できます。

でも、こう、個人的な推測なのですが……おそらくDaVinci Resolve で何か作業を自動化したいと考えた時、8割くらいは「クリップを自動配置したい」という動機でスクリプトを組もうとするんじゃないか? と思ったんです。(偏見)

特にソフトウェアトーク動画(実況・解説・劇場etc)などは音声と一緒に字幕配置することも多いでしょう。
有償版では自動字幕作成機能が付いていますが、ソフトウェアトーク動画のように既に字幕用テキストがある場合はそちらを使うでしょうし、そうでなくてもText+クリップでアニメーションなどをつけたい人もいらっしゃるでしょうし。

そんなわけで、今回はMediaPoolオブジェクトのAppendToTimelineメソッドについて解説していきます。



AppendToTimelineメソッドの使い方

AppendToTimelineメソッドについて

APIドキュメントを読むとMediaPool.AppendToTimelineメソッドは3つあります。

  • AppendToTimeline(clip1, clip2, ...)

  • AppendToTimeline([clips])

  • AppendToTimeline([{clipInfo}, ...])

3つの内、上2つはクリップをタイムラインの末尾へ隙間なくズラッと並べるだけです。配置タイミングは弄れません。
今回使うのは3つ目、太字のやつです。これは配置するトラックや再生位置等を指定できます。

説明用ソースコード(Python版)

先に簡単なPython版ソースコードを載せておきましょう。
Luaで組む人は適宜読み替えてください。

# PythonでAppendToTimelineで指定位置に配置する例(最低限)

project = resolve.GetProjectManager().GetCurrentProject()
pool = project.GetMediaPool()

# 1.配置するクリップを取得
cliplist = pool.GetCurrentFolder().GetClipList()    # カレントフォルダのクリップ一覧を取得
add_clip = None
for clip in cliplist :  # 目的のクリップを検索
    if clip.GetClipProperty('Clip Name') == 'jimaku' :    # 今回は「jimaku」というクリップを検索
        add_clip = clip
        break
if add_clip is None :   # 目的のクリップが見つからない場合、中断 
    print('字幕クリップが見つかりません。処理を中断します。')
    return
                    

# 2.クリップ配置時の設定(dict型に格納)
timeline_fps = project.GetSetting('timelineFrameRate')  # タイムラインのフレームレート取得
clip_fps = add_clip.GetClipProperty('FPS')             # クリップのフレームレート取得
clip_len_second = 10.0              # 配置する際のクリップの長さ(秒)
add_second = 10.0                   # タイムラインへ配置するタイミング(秒)
info = {'mediaPoolItem':add_clip ,  # 追加するクリップ
        'startFrame':0,        # 追加アイテムのトリミング開始フレーム(クリップFPSに依存)
        'endFrame':clip_len_second * 60,  # 追加アイテムのトリミング終了フレーム(クリップFPSに依存)
        #'mediaType':1,        # 動画の映像と音声でトラック番号をずらしたい場合などに指定する
        'trackIndex':2,        # トラック数より大きい場合、その分のトラックを追加する
        'recordFrame':add_second * timeline_fps }    # タイムライン上の配置フレーム(タイムラインFPSに依存)

# 3.クリップをタイムラインへ配置
pool.AppendToTimeline([info])  # 配置するクリップが1つだったとしても、
                               # ClipInfoは必ずlist型に格納してから引数に渡すこと

前準備

AppendToTimelineメソッドはメディアプール内のクリップしか配置できません。
そのため、字幕用のText+クリップを配置したいという人は、事前にメディアプールへひな型となるText+クリップをコピーしておく必要があります。

字幕用クリップはメディアプールへコピーしておくこと


1.配置するクリップの取得

まずは配置したいクリップを取得しましょう。
上のソースコードではMediaPool.GetCurrentFolder()でフォルダを選択し、GetClipList()でフォルダ内のクリップ一覧を取得しています。

GetCurrentFolder()はメディアプールで表示中のフォルダを返しますが、決まったフォルダに字幕クリップなどを格納している場合、GetRootFolder()やGetSubFolderList()、それからGetName()を活用して該当フォルダを探してください。(今回はGetCurrentFolder()で十分なので省略します)

GetClipList()でクリップ一覧を取得したら、for文で順番にクリップ名を比較して探します。
クリップ名の取得にはMediaPoolItem.GetClipProperty('Clip Name')を使いましょう。GetName()ではText+クリップのクリップ名を取得できないので。
(詳しくは過去記事参照 ↓)


2.クリップ配置時の設定

配置するクリップを見つけたら、今度は配置設定をdict型に格納します。
設定できる項目は以下の6つ。

  • mediaPoolItem:配置するクリップ(必須)

  • startFrame:追加クリップのトリミング開始フレーム(int)

    • 省略するとクリップの始めからとなる(初期値が0)

    • 指定する際のフレームはクリップのFPSに依存する(クリップが60FPSの場合、1秒を指定したいなら60に設定する)

  • endFrame:追加クリップのトリミング終了フレーム(int)

    • 省略するとクリップ全体が配置される

    • 指定する際のフレームはクリップのFPSに依存する(クリップが60FPSの場合、1秒を指定したいなら60に設定する)

  • mediaType:配置するトラックの種類(int)

    • 省略した場合:映像と音声の内、適切なトラックに配置(動画クリップの場合は両方)

    • 1を指定:映像トラックのみに追加

    • 2を指定:音声トラックのみに追加

  • trackIndex:配置先のトラック番号(int)

    • 省略した場合:アクティブなトラックが対象となる

    • 入力値の範囲:1~トラック数+1

    • 現在のトラック数+1を指定すると、その分のトラックを追加する

    • 現在のトラック数+2以上を指定すると、アクティブなトラックがあればそこが対象となり、ない場合は配置されない

      • 例:トラックが2つしかない場合、3を指定すると3番目のトラックが自動追加されるが、4以上を指定するとトラックは追加されないしクリップも配置されない

      • Text+や画像など、映像のみのクリップは映像トラックが追加される

      • wavファイルなど、音声のみのクリップは音声トラックが追加される

      • 動画ファイルのように映像と音声の両方を持つクリップは、映像と音声トラックがそれぞれ追加される

例:映像トラックは3番、音声トラックは1番がアクティブな場合
  • recordFrame:タイムラインへの配置タイミングフレーム(int)

    • 省略するとタイムラインの一番最後へ追加される

    • フレームレートはタイムラインのFPSに依存する(タイムラインが24FPSの場合、1秒を指定したいなら24に設定する)

字幕用のText+クリップの長さを音声クリップなどに合わせて調整したい場合、endFrameを調整します。
ひな型となるText+クリップの長さは関係ありません。
メディアプールにコピーした時点で5秒の長さしかなくても、配置時に10秒の長さに設定とかできます。

(動画クリップだったり、Text+クリップでもアニメーションが付いてる場合は試してないのでわかりませんけれど)

あと気を付けたいのはクリップとタイムラインのフレームレートが異なる場合でしょうか。片方のフレームレートをもう片方にも適用して計算したら、なんかクリップの長さや配置位置が思ってたのと違う……ということもあるかもしれません。

上のソースコードではクリップとタイムラインのフレームレートが異なる場合を考慮し、それぞれのフレームレートから10秒分のフレーム数に変換しています。

クリップのフレームレートはMediaPoolItem.GetClipProperty('FPS')
タイムラインのフレームレートはproject.GetSetting('timelineFrameRate')
で取得できます。


3.クリップをタイムラインへ配置

クリップ配置設定をリストに格納したら、AppendToTimeline()へ引数として渡して実行すればクリップを配置できます。

一応気を付けて欲しいのですが、クリップ配置設定が一つだったとしてもリストに格納することを忘れないでください。
リストに格納せずに引数として渡すとアプリが落ちます。(実体験)



注意点

配置済みクリップと干渉するとどうなるのか?

AppendToTimelineで配置しようとしたら、配置済みのクリップと一部被ることもあるでしょう。

配置済みのクリップと干渉した場合、配置済みのクリップが優先されます。
これから配置するクリップの前後が配置済みのクリップに干渉しないようにトリミングされたり、そもそも配置できなかったりします。

また、動画クリップを配置する場合、映像・音声トラックの両方で干渉判定がされるようです。映像トラックで干渉しなくても、音声トラックで何か干渉すると上手く配置できません。(逆も同様)

例:この状態で動画クリップをトラック番号1番の2秒へ配置しよう
とすると、音声トラックが干渉して失敗する

配置済みのクリップを削除したいなら、Timeline.GetItemListInTrack(trackType, index)を利用して干渉しそうなクリップを取得し、Timeline.DeleteClips([timelineItems], Bool)で削除できます。
「配置先のトラックに何か残っている場合、残っているクリップを全削除するかどうか確認する処理」を追加するのも良いかもしれませんね。

トラック番号が追加されるパターン、されないパターン

また、トラック番号の干渉も気を付けなければいけません。
trackIndexの項目に「現在のトラック数+1」を指定するとトラックが追加されますが、「現在のトラック数+2以上」を指定するとトラックが追加されないというややこしい仕様になっています。
(2024/6/25時点の話。不具合?)

トラックの自動追加を当てにすると誤動作の原因になるため、トラック番号は「1~現在のトラック数」に指定する方が良いでしょう。
現在のトラック数はTimeline.GetTrackCount(trackType)で取得できます。
(trackTypeは"video"で映像、"audio"で音声、"subtitle"で字幕トラックを指定)



あとがき

本当は実際に作った「配置済みの音声に合わせて字幕配置するスクリプト」を紹介しようと思ったのですが、説明動画がないとわかりにくくなってしまったので今回は省略しました。
動画が出来たら後日改めて記事を投稿する予定です。

そういえばDaVinci Resolveのver.19のパブリックベータ版がリリースされていますね。APIにも色々機能が追加されているようです。
タイムラインとかクリップ周りの操作がもっと楽になると良いのですが。

今回の記事もお役に立てば幸いです。

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