用脚本或流水线应用程序操控 Bernard Review。包括协议、Python 客户端、按系列划分的所有命令、事件以及完整示例。
Bernard Review 可以由 Python、Maya、Nuke、Houdini、生产 tracker,或任何能打开 TCP 连接的语言来操控。艺术家手动完成的每一件事都有对应的命令:打开片段、播放、对比、调色、导出、开始会话、发布备注。本页足以让您实现播放器的自动化;逐字段的完整参考是 API 参考(英文;也可通过 Help > API Documentation 打开)。
127.0.0.1,默认端口 5556。使用 --ipc-port N 启动的播放器监听 N:这样同一台机器上就可以运行两个播放器。\n 结尾,带有 "cmd" 字段:{"cmd": "seek", "frame": 24}。{"status": "ok", "cmd": "seek", ...} 或 {"status": "error", "cmd": "seek", "reason": "..."}。错误总是附带一个用平实语言写成的原因,绝不会等到您的超时。没有请求 ID:应答通过其 "cmd" 与请求对应。{"event": ...})在同一连接上到达,与应答混杂在一起(见下文)。Host: 头)会被直接关闭,不执行任何内容:网页无法操控播放器。一行最多 16 MiB。无需编写代码就能试用:Window > Console(Ctrl+Shift+C)可以在播放器内部发送同样的命令,并支持 Tab 补全:status、seek {"frame": 24},或完整的 JSON 形式。在执行写文件、发布或关闭播放器的命令之前,它会先询问。

bernard_api.py 用一个类 BernardClient 封装了该协议,每个命令对应一个方法。它安装在播放器旁边的 api 文件夹中:
| 系统 | 位置 |
|---|---|
| Windows | C:\Program Files\Bernard Review\bin\api\bernard_api.py |
| Linux (RPM) | /usr/share/bernardplayer/api/bernard_api.py |
Linux(.sh 归档) | <install folder>/share/bernardplayer/api/bernard_api.py |
它只需要 Python 3 的标准库。
import sys
sys.path.append(r"C:\Program Files\Bernard Review\bin\api")
from bernard_api import BernardClient
client = BernardClient(host="127.0.0.1", port=5556)
if not client.connect():
raise SystemExit("Bernard Review does not answer on port 5556")
reply = client.open_media("D:/shots/SQ010_SH010_ANIM_v002.mov")
if reply is None or reply.get("status") == "error":
print("refused:", reply and reply.get("reason"))
else:
client.play()
request(dict) 发送一个命令并等待它的应答(一个 dict),包括错误:对于播放器的拒绝,它不会抛出异常;超时或连接丢失时返回 None。send_command(dict) 发送后不等待。play()、seek()、set_exposure()、export() 等)调用其中之一;返回数据的方法通过 request()。on("frame_changed", function) 为一个事件订阅一个函数;由后台线程读取连接。不使用客户端,几行代码就够了:
import json, socket
with socket.create_connection(("127.0.0.1", 5556)) as s:
f = s.makefile("rw", encoding="utf-8", newline="\n")
f.write(json.dumps({"cmd": "status"}) + "\n"); f.flush()
for line in f:
msg = json.loads(line)
if msg.get("cmd") == "status": # skip the events
print(msg["playback"]["currentFrame"]); break
seek、set-in、set-out 和 --frame 选项使用的是片段中的位置,从 0 开始计数,而不是标尺上打印的编号。在从 1001 开始的片段上,显示的帧 1010 对应位置 9。status 给出位置(playback.currentFrame)和第一帧的编号(playback.startOffset)。open 在探测片段之前就返回应答:status.playback.transitioning 一直为 true,直到片段显示在画面上。export 把任务加入队列:用 export-status 或 export-done 事件来跟踪。export-notes 在后台写入文件。set-proxy 之后,请等待 status.viewport.retiering 回到 false。{"cmd": "set-ui-level", "value": "complete"}。quit 先应答,然后干净地关闭播放器,不会询问是否保存:如果审阅内容重要,请先发送 save-playlist 或 export-notes。播放器的 115 个命令。括号中的字段是主要字段;track 为 "A"(默认)或 "B"。
播放与范围
| 命令 | 作用 |
|---|---|
play、pause、reverse-play | 播放、暂停、倒放 |
seek (frame) | 跳到某个位置(从 0 开始) |
step-frame (delta) | 向前或向后步进 delta 帧 |
toggle-loop | 循环该范围 |
set-playlist-playback (loop_mode 0、1 或 2,dont_wait_incomplete_shots) | 关闭循环、循环片段或循环播放列表 |
set-in、set-out (frame,可选) | 入点和出点;不带 frame 时使用播放头 |
clear-in-out、set-in-out-lock (value) | 清除范围;禁止用鼠标移动它 |
set-fps (value)、set-start (value) | 帧率;第一帧的编号 |
set-volume (value 0 到 1)、set-mute (value)、toggle-mute | 声音 |
片段与播放列表
| 命令 | 作用 |
|---|---|
open 或 load (path) | 在轨道 A 上打开文件或序列,并添加到播放列表 |
load-playlist (path) | 载入 .bpl、.otio、.csv、.json 或 .edl 播放列表 |
save-playlist (path) | 把播放列表写为 .bpl(备注、状态、调色、绘制内容) |
playlist-add (path)、playlist-play (index)、playlist-remove (index)、playlist-move (from, to)、playlist-clear | 管理播放列表(索引从 0 开始) |
drop (paths,at:track_a、track_b 或 viewport_b) | 等同于从文件管理器拖入文件 |
对比与版本
| 命令 | 作用 |
|---|---|
set-ab-mode (value)、toggle-ab | A/B 模式 |
set-track-b (path) | 把文件放到轨道 B 上 |
set-ab-view (value:a、wipe、b)、ab-flip | 只看 A、擦除对比、只看 B;交换 A/B |
set-wipe (position 0 到 1,angle 单位为度) | 擦除对比的位置和角度 |
cycle-b (direction:prev、next) | B 上的上一个或下一个版本 |
pin-track-b (value)、set-b-version-preload (value) | 固定 B;预加载相邻版本 |
set-ab-label-mode (interaction、always、never)、set-metadata-track (a、b、ab) | A/B 字母;Metadata 选项卡显示的轨道 |
build-matrix (sequence, id, shots)、get-matrix | 填充和读取 Version Board(参见集成) |
色彩
| 命令 | 作用 |
|---|---|
set-exposure、set-gamma (value, track) | 曝光(单位为档)、伽马 |
set-white-balance (temp,tint 取值 -1 到 1,track)、set-offset (value:[r, g, b],track) | 白平衡、偏移 |
set-colorspace (value) | 轨道 A 的输入空间:ACEScg、sRGB、AP0、AdobeRGB、ProPhoto、Rec709、LogC3、LogC4,或 Auto |
set-channel (value:RGBA、R、G、B、A、L;track) | 显示的通道 |
set-stage (stage, on, track) | 关闭或开启某个环节(exposure、levels、curves、gamma 等) |
set-curve (channel:master、r、g、b;points 或 reset) | 曲线,ACEScct 轴上的 [x, y] 点 |
set-hue-range (range, hue, saturation, lightness) | 色相范围 |
color-panel (target, before_after, picker, levels_auto, preset_save, preset_apply...) | 色彩面板;不带任何字段时读取它 |
scopes (open, kind) | 示波器及其最近的测量值(直方图、裁切) |
set-layer (track_idx, layer_idx)、layer-info (track) | 多图层 EXR 的通道 |
查看器、界面和窗口
| 命令 | 作用 |
|---|---|
zoom (value,1 = 每个源像素对应一个屏幕像素)、pan (x, y)、fit、flip | 取景 |
set-fullscreen (value)、set-window-size (width, height)、set-ui-scale (percent) | 主窗口 |
set-theme (dark、light、neon、system;或 sombre、clair、systeme)、set-ui-level (essential、complete) | 显示模式和界面级别 |
reset-layout、new-window (view)、close-window (name 或 all)、windows | 布局和面板副本 |
contact-sheet (open, mode, card_w...) | 联系表 |
set-tool (tool:pen、text、arrow、rect、laser、eraser、pipette、select) | 绘图工具 |
debug-mouse (x, y, down, alt, release) | 模拟鼠标,用于界面测试 |
备注、截图与导出
| 命令 | 作用 |
|---|---|
export-notes (output_dir) | 不弹出任何对话框,直接写出 export.json 和 export.html |
screenshot (output, frame, annotations) | 轨道 A 的片段的 PNG,与屏幕上一样已调色 |
export (output, preset, source, playlist, format, codec, color, burn_in, annotations, watermark, recipient...) | 导出帧或视频;加入队列 |
export-status、export-cancel、export-presets | 跟踪、取消、列出预设 |
export-recipe (action:list 或 run;name、file 或 recipe;clips, recipient) | 导出方案 |
内存与解码
| 命令 | 作用 |
|---|---|
set-proxy (proxy_idx:0 = 1/1,1 = 1/2,2 = 1/4,3 = 1/8,4 = Smart RAM-Fit) | 画面上的片段的解码分辨率 |
set-slow-decode-tier (auto, off) | 解码跟不上时 |
set-gpu-decode (value) | NOVA 的 GPU 解码(beta):开、关,或查询状态 |
set-gpu-yuv (value) | 视频的 GPU YUV 上传(beta):开、关,或查询状态 |
set-gpu-video-decode (value) | GPU 视频解码(beta):开、关,或查询状态 |
set-gpu-prores (value) | GPU ProRes 解码(beta):开、关,或查询状态 |
set-ram-limit-gb、set-vram-ring-limit-gb (value;VRAM 为 0 表示 Auto) | 内存预算 |
set-hardware-decode (value) | 硬件解码 |
ram-fit-apply、precache-playlist (value)、full-quality (value)、cache-clip-frames (clip_id) | Smart RAM-Fit、预加载 |
ram-info (frames) | 内存使用情况,逐个片段 |
cache-info、cache-purge (scope) | 压缩缓存:已存在,但在此版本中仍为空 |
审阅会话
| 命令 | 作用 |
|---|---|
session-create (name, user_name, password,reach:network 或 this_computer) | 主持;应答中给出链接 |
session-join (address, user_name, password)、session-leave | 加入、离开 |
session-status | 完整的会话状态:参与者、主控者、语音等 |
session-pass-baton (participant_id)、session-set-sync (locked) | 移交控制权;Local Review |
chat-send (text)、chat-log (last) | 聊天 |
laser (x, y, active)、laser-status | 激光笔 |
voice-test (seconds) | 通过语音扬声器播放一个提示音 |
stream-enable (on, width, height)、stream-status | 向网页来宾串流 |
Tracker(任何请求都不含机密信息)
| 命令 | 作用 |
|---|---|
tracker-sites | trackers.json 中的站点 |
tracker-connect (site)、tracker-disconnect (site, forget) | 连接 |
tracker-projects、tracker-playlists (project_id) | 浏览 |
tracker-load-playlist (playlist_id,mode:replace 或 append) | 载入播放列表 |
tracker-publish (items, status, dry_run) | 发布备注 |
tracker-download-media (index)、tracker-cancel | 下载预览;取消 |
诊断
| 命令 | 作用 |
|---|---|
status | 播放器的完整状态(见下文) |
system-info | 版本、系统、显卡、库;不含姓名,不含路径 |
dump-thumbnails (output, track) | 把时间线的缩略图输出为一张 PNG 图 |
quit | 干净地关闭播放器 |
播放器会主动向其客户端广播这些行:
| 事件 | 字段 |
|---|---|
play、pause | — |
frame_changed | frame:位置,每当它改变就发出(播放、拖动、跳转) |
export-done | ok, cancelled, error, frames_written, output, jobs, seconds, encoder |
tracker-connected | ok, site, user, reason |
tracker-projects、tracker-playlists | ok,projects 或 playlists,reason |
tracker-loaded | ok, items, missing_media, reason |
tracker-publish-done | published, skipped, failed, dry_run |
tracker-download-done | index, ok,path 或 reason |
status {"cmd": "status"} 返回完整状态。最有用的块:playback(state、currentFrame、startOffset、fps、ab_mode、ab_view、transitioning,以及 late_frames 和 lost_frames 计数器)、color(轨道 A 的调色、通道)、viewport(解码分辨率和原始分辨率、proxy_idx、retiering、zoom)、decode(解码时间、too_slow)、track_b、ram_fit 和 playlist(每个片段一项)。
打开最新的渲染并播放(例如从 Nuke 的按钮):
client.open_media("D:/renders/SQ010_SH010_COMP_v003/SQ010_SH010_COMP_v003.1001.exr")
client.set_colorspace("ACEScg")
client.play()
跟随播放头(例如让 Maya 的时间线保持同步):
client.on("frame_changed", lambda e: print("position", e["frame"]))
client.on("play", lambda e: print("playing"))
导出样片并等待完成:
client.export("D:/dailies/<clip>.mov", preset="dailies_prores_lt",
playlist=True, burn_in=True)
result = client.wait_for_export()
print(result["state"], result.get("error"))
收集一次审阅的备注:
import json, os, time
out = "D:/review/SQ010_notes"
client.export_notes(out)
time.sleep(2) # the files are written in the background
notes = json.load(open(os.path.join(out, "export.json"), encoding="utf-8"))
开始一个受密码保护的审阅会话:
r = client.session_create(name="SQ010 dailies", password="...")
for link in r["links"]:
print(link["kind"], link["link"]) # lan, vpn...
api 文件夹中包含所交换文件的 JSON schema:playlist.schema.json(.bpl 播放列表,带有 tracker 标识符的 x_tracking 块)、notes_payload.schema.json(备注的 export.json)和 export_recipe.schema.json(导出方案),以及 export_examples/ 中的导出任务示例。