Blenderで動画編集時にSubRip形式の字幕ファイルも編集したいので、 Video Sequence Editor のプレイヘッドのタイムスタンプを取得したい。
やりたいことは以下になる。
- VSEのコンテキストメニューから呼び出したい
- タイムスタンプをクリップボードにコピーしたい
- プレイヘッドの位置(フレーム番号)をタイムスタンプに変換したい
解決策
実現方法を整理する
VSEのコンテキストメニューを拡張する
SEQUENCER_MT_context_menu
がVSEのコンテキストメニューのようだ。
以下でメニューを追加可能
def menu_fn(self, context):
self.layout.separator()
self.layout.operator(xx.bl_idname) # オペレーターは要実装
bpy.types.SEQUENCER_MT_context_menu.append(menu_fn)
アドオン内でクリップボードに文字列をコピーする
clipboard # WindowManager(ID) — Blender Python API
timestamp = "00:00:00,123"
context.window_manager.clipboard = timestamp # timestampがクリップボードにコピーされる
プレイヘッドが指しているフレームナンバーを取得する
以下で取得できる。
cur_frame = bpy.context.scene.frame_current
フレームNoをタイムスタンプに変換する
フレームNoを秒に変換するためには、フレームレートを知る必要がある。
VSEでは以下で、フレームレートが計算できるようだ。
frame_rate = bpy.context.scene.render.fps / bpy.context.scene.render.fps_base
あとは、以下でフレームNoをtimedelta
に変換できる。
sec = cur_frame / frame_rate
dlt = datetime.timedelta(seconds=sec)
実装例
srt_loader/init.py at main · kantas-spike/srt_loaderに実装。
以下はメニュー部分のみ抜粋
import bpy
import datetime
class StrLoaderGetTimestampOfPlayhead(bpy.types.Operator):
bl_idname = "srt_loader.copy_timestamp_of_playhead"
bl_label = "Copy playhead timestamp"
bl_description = "Playheadのタイムスタンプを取得する"
@classmethod
def poll(cls, context):
return context.space_data.view_type == "SEQUENCER"
def format_srt_timestamp(self, delta):
m, s = divmod(delta.seconds, 60)
h, m = divmod(m, 60)
return "{:02}:{:02}:{:02},{:03}".format(
h, m, s, round(delta.microseconds / 1000)
)
def execute(self, context):
frame_rate = bpy.context.scene.render.fps / bpy.context.scene.render.fps_base
cur_frame = bpy.context.scene.frame_current
delta = datetime.timedelta(seconds=(cur_frame / frame_rate))
timestamp = self.format_srt_timestamp(delta)
print(
f"frame_rate: {frame_rate}, cur_frame: {cur_frame}, timestamp: {timestamp}"
)
self.report({"INFO"}, timestamp)
context.window_manager.clipboard = timestamp
return {"FINISHED"}
def menu_fn(self, context):
self.layout.separator()
self.layout.operator(StrLoaderGetTimestampOfPlayhead.bl_idname)
classes = [
StrLoaderGetTimestampOfPlayhead,
]
def register():
for c in classes:
bpy.utils.register_class(c)
bpy.types.SEQUENCER_MT_context_menu.append(menu_fn)
def unregister():
bpy.types.SEQUENCER_MT_context_menu.remove(menu_fn)
for c in classes:
bpy.utils.unregister_class(c)
if __name__ == "__main__":
register()
参考
- clipboard # WindowManager(ID) — Blender Python API
- Blenderでシェイプキー名一覧を取得・一覧から空のシェイプキーを作成 #Python - Qiita
- python - VSE playhead position variable - Blender Stack Exchange
- python - What does this do: fps = scene.render.fps / scene.render.fps_base? - Blender Stack Exchange blender/scripts/startup/bl_ui/space_sequencer.py at 9c0bffcc89f174f160805de042b00ae7c201c40b · blender/blender