Premiere+Python审片工具开发

前言

这篇文章主要是给使用Premiere作为审片工具的公司,以及他们的TD提供一些工作量
通过开发一些工具来提升审片工作的效率,让导演和制片少加班,早回家!

开发借用pymiere 项目,支持的pr版本2017-2023。
阅读能力强的同学可以直接点开github看他的说明(就不用看这篇流水账啦)。

文章大致内容如下

  • 如何安装premiere的开发环境
  • 提供一些审片需求以及代码段
    • 批量导入某一场视频,创建层级结构
    • 整体切换环节
    • 检查/更新review版本
    • 提交反馈
    • 颜色标记任务状态

环境配置

需要给Premiere安装pymiere扩展,使用正版的同学可以直接通过扩展管理器安装。
用学习版的同学,需要使用一个第三方软件来安装扩展包,下面是安装步骤。

1.首先下载安装 ZXP/UXP Installer
只勾选下面这个,然后安装。

2.打开ZXP Installer软件,安装扩展
下载之前提到的pymiere扩展,然后File菜单打开zxp文件进行安装(或者直接将zxp文件拖拽进窗口就行)。

3.看到successfully就是安装完成了

4.打开pr在菜单栏,能看到Pymiere Link代表成功安装

5.最后在你的python环境中安装第三方库

1
pip install pymiere

概念与文档

这是pymiere库文档: https://ppro-scripting.docsforadobe.dev/
比较重要的是ProjectItemTrackItem两个对象。

ProjectItem是项目素材库中音视频媒体对象。
通常创建bin文件夹,导入/替换视频,或者获取视频信息等方法在这个对象里。

TrackItem是剪辑线中的剪辑片段(clip)对象。
比如获取剪辑入点/出点,时间长度,timecode等操作在这个对象里。

常用代码块

重要: 运行代码时,必须打开pr软件,并进入一个工程。

获取当前激活的项目对象

这是一切的基础,获取project对象才能对pr进行操控。

1
2
3
import pymiere

project = pymiere.objects.app.project

创建bin文件夹

1
bin_folder = project.rootItem.createBin('abc')

导入视频

1
2
3
4
5
project.importFiles(filePaths=mov_list,          # 导入的mov路径,列表类型
suppressUI=True, # 是否应禁止显示警告对话框。
targetBin=bin_folder, # 目标文件夹的路径,ProjectItem对象
importAsNumberedStills=False # 是否为序列帧导入
)

将视频放在时间线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pymiere  

mov_path = r'D:\test\sc001_shot001_lay_v001.mov'
# 获取pr软件中,当前激活的项目对象
project = pymiere.objects.app.project

# 获取激活的序列
sequence = project.activeSequence

# 通过视频路径,获取其ProjectItem对象
item = project.rootItem.findItemsMatchingMediaPath(mov_path, ignoreSubclips=True)[0]

# 选择第一个视频轨道
track = sequence.videoTracks[0]

# 在时间轨道0秒处插入视频
track.insertClip(item, 0)

获取剪辑线选择的视频clip

1
2
3
4
5
6
7
8
9
10
11
# 获取激活的序列对象
active_sequence = project.activeSequence

# 获取选择的clip,会返回一个数组对象pymiere.core.Array
selected = active_sequence.getSelection()

# 过滤出所有的视频类型
for i in range(selected.length):
track_item = selected[i] # 这里是TrackItem对象
if track_item.mediaType == 'Video':
print(track_item)

替换视频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 先通过上面的方法获取TrackItem对象

# 然后从TrackItem获取素材箱中媒体对象
project_item = track_item.projectItem

# 指定新的mov路径
new_mov_path = r'D:\test\sc001_shot001_lay_v001.mov'
name = os.path.basename(new_mov_path)

# 执行替换
project_item.changeMediaPath(new_mov_path, overrideChecks=True)

# 修改素材箱中媒体名称
project_item.name = name

# 修改剪辑线上clip名称
track_item.name = name

需求与实例

批量导入视频,创建层级

这里的例子是导入sc001sc002两个场次,所有lay环节的最新版review。
并在pr的素材箱中创建层级结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pymiere  

# 获取pr软件中,当前激活的项目对象
project = pymiere.objects.app.project

# 创建文件夹层级
sequence_name = 'sc001'
seq_bin_folder = project.rootItem.createBin(sequence_name)
step_bin_folder = seq_bin_folder.createBin('lay')

# 导入mov文件
mov_list = [rf'D:\lay\{sequence_name}_shot001_lay_v003.mov',
rf'D:\lay\{sequence_name}_shot002_lay_v003.mov',
rf'D:\lay\{sequence_name}_shot003_lay_v003.mov',
rf'D:\lay\{sequence_name}_shot004_lay_v003.mov']

# 导入操作
project.importFiles(mov_list,
suppressUI=True,
targetBin=step_bin_folder,
importAsNumberedStills=False
)

切换环节

将现在的lay环节替换为ani环节的mov

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import os  
import pymiere

# 获取pr软件中,当前激活的项目对象
project = pymiere.objects.app.project

# 获取文件夹层级下所有的mov(projectItem对象)
sequence_name = 'sc001'
step_name = 'lay'
target_step_name = 'ani'

project_items = []
# 遍历素材箱
for root_bin_folder in project.rootItem.children:
# 如果根目录名称为sc001,则遍历其子项
if root_bin_folder.name == sequence_name and not root_bin_folder.isSequence():
for num in range(root_bin_folder.children.numItems):
step_bin_item = root_bin_folder.children[num]
# 如果bin目录为step名称,则遍历其子项
if step_name == step_bin_item.name and not step_bin_item.isSequence():
# 修改bin目录名称为ani
step_bin_item.name = target_step_name
for video_num in range(step_bin_item.children.numItems):
# 最后将所有sc001/ani目录下的媒体对象加入列表
project_items.append(step_bin_item.children[video_num])

for project_item in project_items:
# 获取媒体文件的路径
old_file_path = project_item.getMediaPath()
# 粗暴的获取目标环节的mov路径,实际使用中需构建自己的逻辑
new_file_path = old_file_path.replace(step_name, target_step_name)
# 执行替换
project_item.changeMediaPath(new_file_path, overrideChecks=True)
# 修改素材箱中的名称
project_item.name = os.path.basename(new_file_path)

素材箱中的媒体文件替换后,时间线上的clip也会随之替换。

检查/更新review版本

思路和上面一样,遍历素材箱找到对应媒体对象,然后进行替换。

或者只替换时间线上使用的mov:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pymiere  

clips_list = []

# 获取pr软件中,当前激活的项目对象
project = pymiere.objects.app.project

# 获取激活的序列对象
active_sequence = project.activeSequence

# 获取序列对象所有的视频轨对象
video_tracks = active_sequence.videoTracks

for track_num in range(video_tracks.numTracks):
# 单个视频轨道的所有剪辑块 clips
clips = video_tracks[track_num].clips
for clip_num in range(clips.numItems):
clips_list.append(clips[clip_num])

for track_item in clips_list:
project_item = track_item.projectItem
# 执行替换
project_item.changeMediaPath(new_file_path, overrideChecks=True)

提交反馈

这个也是获取时间线上选择的视频,写一些界面交互让审核者提交文字反馈或截图。

pymiere提供了一个时间线跳转的方法,可以帮助快速定位到指定的镜头:

1
2
3
4
5
6
import pymiere

project = pymiere.objects.app.project

# 跳转时间线到指定的时间
project.activeSequence.setPlayerPosition(clip.start.ticks)

印象中clip.start.ticks会出现一个类型错误,需要改源码进行修正。

颜色标记镜头任务状态

这里使用marker对剪辑线进行标记,修改颜色和反馈/制作内容。
可以根据不同的颜色定义不同的任务状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pymiere  

project = pymiere.objects.app.project
active_sequence = project.activeSequence
clips = active_sequence.getSelection()

notes = ['修改桌子的边缘高光', '角色A走路飘移', '屋顶换成玻璃材质']
n = 0
for clip in clips:
# 创建Marker
marker = active_sequence.markers.createMarker(time=clip.start.seconds)
# 设置Marker时间范围等于clip的范围
marker.start = clip.start.seconds
marker.end = clip.end.seconds
# 设置文字描述
marker.comments = notes[n]
# 设置Marker颜色
marker.setColorByIndex(4)
n += 1

如果想要用标签色来标记任务状态,需要修改pymiere\objects\premiere_objects.py文件中的TrackItem类。pymiere没有提供对应方法来修改标签颜色。

总结

Pymiere库并不是官方提供的Python API,它的作用主要是将 Python 命令(获取属性、执行函数等)转换为 ExtendScript 代码,然后通过HTTP请求将代码发送给Pymiere Link扩展来执行它。

所以提供的接口有限,能实现的自动化也因此受到限制。不过可以查询ExtendScript命令去修改pymiere源码来实现想要的效果。

开发体验来说不如ShotGrid RVNuke Studio,两者都提供了官方Python API,文档详细且接口丰富。

文章就到这里,如果有所帮助可以关注一下这个公众号,感谢!