DOCUMENTACIÓN PARA DESARROLLADORES

API de Python e IPC

Controle Bernard Review desde un script o una aplicación del pipeline. El protocolo, el cliente de Python, cada comando por familia, los eventos y ejemplos completos.

Bernard Review puede controlarse desde Python, Maya, Nuke, Houdini, un tracker de producción o cualquier lenguaje capaz de abrir una conexión TCP. Todo lo que un artista hace a mano tiene su comando: abrir clips, reproducir, comparar, corregir el color, exportar, iniciar una sesión, publicar notas. Esta página basta para automatizar el reproductor; la referencia exhaustiva, campo por campo, es la referencia de la API, en inglés (también abierta por Help > API Documentation).

El protocolo

  • Dirección: 127.0.0.1, puerto 5556 por defecto. Un reproductor iniciado con --ipc-port N escucha en N: así es como dos reproductores funcionan en la misma máquina.
  • Formato: JSON Lines. Cada petición es un objeto JSON en una línea, terminada con \n, con un campo "cmd": {"cmd": "seek", "frame": 24}.
  • Una respuesta por petición, en el orden de envío, normalmente en unos pocos milisegundos: {"status": "ok", "cmd": "seek", ...} o {"status": "error", "cmd": "seek", "reason": "..."}. Un error siempre lleva un motivo en lenguaje llano y nunca espera a su tiempo de espera. No hay identificador de petición: una respuesta se asocia a su petición por su "cmd".
  • Los eventos del reproductor ({"event": ...}) llegan por la misma conexión, mezclados con las respuestas (véase más abajo).
  • Un solo cliente a la vez. Una segunda conexión espera a que se cierre la primera.
  • Solo en local. El puerto escucha en el loopback. Una conexión que parece la petición de un navegador (una línea HTTP, una cabecera Host:) se cierra sin ejecutar nada: una página web no puede controlar el reproductor. Una línea contiene como máximo 16 MiB.
  • Ningún secreto pasa por este puerto en lo que respecta a los trackers: una petición que lleve una contraseña, una clave o un token de tracker se rechaza.

Para probarlo sin escribir código: Window > Console (Ctrl+Mayús+C) envía los mismos comandos desde el propio reproductor, con autocompletado con Tab: status, seek {"frame": 24}, o la forma JSON completa. Pregunta antes de los comandos que escriben archivos, publican o cierran el reproductor.

La Console con un comando seek y su respuesta, y después el comienzo de la respuesta a status.

El cliente de Python

bernard_api.py envuelve el protocolo en una clase, BernardClient, con un método por comando. Se instala junto al reproductor, en la carpeta api:

SistemaUbicación
WindowsC:\Program Files\Bernard Review\bin\api\bernard_api.py
Linux (RPM)/usr/share/bernardplayer/api/bernard_api.py
Linux (archivo .sh)<install folder>/share/bernardplayer/api/bernard_api.py

No necesita nada más que la biblioteca estándar de 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) envía un comando y espera su respuesta (un dict), errores incluidos: no lanza ninguna excepción por la negativa del reproductor, y devuelve None si se agota el tiempo de espera o se pierde la conexión.
  • send_command(dict) envía sin esperar.
  • Los métodos con nombre (play(), seek(), set_exposure(), export()...) llaman a uno u otro; los que devuelven datos pasan por request().
  • on("frame_changed", function) suscribe una función a un evento; un hilo en segundo plano lee la conexión.

Sin el cliente, bastan unas pocas líneas:

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

Qué saber antes de escribir un script

  • Números de fotograma. seek, set-in, set-out y la opción --frame toman la posición en el clip contada desde 0, no el número impreso en la regla. En un clip que empieza en 1001, el fotograma mostrado 1010 es la posición 9. status da la posición (playback.currentFrame) y el número del primer fotograma (playback.startOffset).
  • Qué es asíncrono. open responde antes de que se sondee el clip: status.playback.transitioning permanece en true hasta que el clip está en pantalla. export pone un trabajo en cola: sígalo con export-status o con el evento export-done. export-notes escribe sus archivos en segundo plano. Tras set-proxy, espere a que status.viewport.retiering vuelva a false.
  • Un perfil nuevo hace la pregunta del primer arranque en una ventana modal: envíe primero {"cmd": "set-ui-level", "value": "complete"}.
  • quit responde y después cierra el reproductor de forma limpia, sin preguntar si se guarda: envíe antes save-playlist o export-notes si la revisión importa.
  • Varias peticiones del mismo nombre en vuelo no se pueden distinguir: envíelas una tras otra.

Comandos, por familia

Los 115 comandos del reproductor. Los campos entre paréntesis son los principales; track es "A" (el valor por defecto) o "B".

Reproducción y rango

ComandoEfecto
play, pause, reverse-playReproducir, pausa, reproducir hacia atrás
seek (frame)Ir a una posición (desde 0)
step-frame (delta)Avanzar o retroceder delta fotogramas
toggle-loopRepetir el rango en bucle
set-playlist-playback (loop_mode 0, 1 o 2, dont_wait_incomplete_shots)Bucle desactivado, sobre el clip o sobre la playlist
set-in, set-out (frame, opcional)Puntos de entrada y de salida; sin frame, el cabezal
clear-in-out, set-in-out-lock (value)Borrar el rango; impedir que el ratón lo mueva
set-fps (value), set-start (value)Frecuencia de imagen; número del primer fotograma
set-volume (value de 0 a 1), set-mute (value), toggle-muteSonido

Clips y playlist

ComandoEfecto
open o load (path)Abrir un archivo o una secuencia en la pista A, añadiéndolo a la playlist
load-playlist (path)Cargar una playlist .bpl, .otio, .csv, .json o .edl
save-playlist (path)Escribir la playlist como .bpl (notas, estados, corrección de color, dibujos)
playlist-add (path), playlist-play (index), playlist-remove (index), playlist-move (from, to), playlist-clearGestionar la playlist (índices desde 0)
drop (paths, at: track_a, track_b o viewport_b)Como soltar archivos desde el explorador de archivos

Comparación y versiones

ComandoEfecto
set-ab-mode (value), toggle-abModo A/B
set-track-b (path)Poner un archivo en la pista B
set-ab-view (value: a, wipe, b), ab-flipSolo A, cortinilla, solo B; intercambiar A/B
set-wipe (position de 0 a 1, angle en grados)Posición y ángulo de la cortinilla
cycle-b (direction: prev, next)Versión anterior o siguiente en B
pin-track-b (value), set-b-version-preload (value)Fijar B; precargar las versiones vecinas
set-ab-label-mode (interaction, always, never), set-metadata-track (a, b, ab)Letras A/B; la pista de la pestaña Metadata
build-matrix (sequence, id, shots), get-matrixRellenar y leer el Version Board (véase Integraciones)

Color

ComandoEfecto
set-exposure, set-gamma (value, track)Exposición (en stops), gamma
set-white-balance (temp, tint de -1 a 1, track), set-offset (value: [r, g, b], track)Balance de blancos, offset
set-colorspace (value)Espacio de entrada de la pista A: ACEScg, sRGB, AP0, AdobeRGB, ProPhoto, Rec709, LogC3, LogC4, o Auto
set-channel (value: RGBA, R, G, B, A, L; track)Canal mostrado
set-stage (stage, on, track)Desactivar o activar una etapa (exposure, levels, curves, gamma...)
set-curve (channel: master, r, g, b; points o reset)Curvas, puntos [x, y] en el eje ACEScct
set-hue-range (range, hue, saturation, lightness)Rangos de tono
color-panel (target, before_after, picker, levels_auto, preset_save, preset_apply...)El panel de color; sin ningún campo, lo lee
scopes (open, kind)Los scopes y sus últimas medidas (histograma, recorte)
set-layer (track_idx, layer_idx), layer-info (track)Pase de un EXR multicapa

Visor, interfaz y ventanas

ComandoEfecto
zoom (value, 1 = un píxel de origen por píxel de pantalla), pan (x, y), fit, flipEncuadre
set-fullscreen (value), set-window-size (width, height), set-ui-scale (percent)Ventana principal
set-theme (dark, light, neon, system; o sombre, clair, systeme), set-ui-level (essential, complete)Modo de visualización y nivel de la interfaz
reset-layout, new-window (view), close-window (name o all), windowsDisposición y copias de paneles
contact-sheet (open, mode, card_w...)Hoja de contactos
set-tool (tool: pen, text, arrow, rect, laser, eraser, pipette, select)Herramienta de dibujo
debug-mouse (x, y, down, alt, release)Ratón simulado, para pruebas de la interfaz

Notas, capturas y exportación

ComandoEfecto
export-notes (output_dir)Escribir export.json y export.html sin ningún cuadro de diálogo
screenshot (output, frame, annotations)Un PNG del clip de la pista A, con la corrección de color como en pantalla
export (output, preset, source, playlist, format, codec, color, burn_in, annotations, watermark, recipient...)Exportar fotogramas o una película; en cola
export-status, export-cancel, export-presetsSeguir, cancelar, enumerar los preajustes
export-recipe (action: list o run; name, file o recipe; clips, recipient)Recetas de exportación

Memoria y decodificación

ComandoEfecto
set-proxy (proxy_idx: 0 = 1/1, 1 = 1/2, 2 = 1/4, 3 = 1/8, 4 = Smart RAM-Fit)Resolución de decodificación del clip en pantalla
set-slow-decode-tier (auto, off)Cuando la decodificación no da abasto
set-gpu-decode (value)Decodificación en GPU para NOVA (beta): activada, desactivada, o el estado
set-gpu-yuv (value)Carga YUV en GPU para películas (beta): activada, desactivada, o el estado
set-gpu-video-decode (value)Decodificación de vídeo en GPU (beta): activada, desactivada, o el estado
set-gpu-prores (value)Decodificación ProRes en GPU (beta): activada, desactivada, o el estado
set-ram-limit-gb, set-vram-ring-limit-gb (value; 0 = Auto para la VRAM)Presupuestos de memoria
set-hardware-decode (value)Decodificación por hardware
ram-fit-apply, precache-playlist (value), full-quality (value), cache-clip-frames (clip_id)Smart RAM-Fit, precarga
ram-info (frames)Uso de memoria, clip a clip
cache-info, cache-purge (scope)Caché de compresión: presente, pero todavía vacía en esta versión

Sesiones de revisión

ComandoEfecto
session-create (name, user_name, password, reach: network o this_computer)Organizar; la respuesta da los enlaces
session-join (address, user_name, password), session-leaveUnirse, salir
session-statusTodo el estado de la sesión: participantes, piloto, voz...
session-pass-baton (participant_id), session-set-sync (locked)Ceder el control; Local Review
chat-send (text), chat-log (last)Chat
laser (x, y, active), laser-statusPuntero láser
voice-test (seconds)Reproducir un tono por el altavoz de la voz
stream-enable (on, width, height), stream-statusRetransmisión a los invitados web

Trackers (ningún secreto en ninguna petición)

ComandoEfecto
tracker-sitesLos sitios de trackers.json
tracker-connect (site), tracker-disconnect (site, forget)Conexión
tracker-projects, tracker-playlists (project_id)Explorar
tracker-load-playlist (playlist_id, mode: replace o append)Cargar una playlist
tracker-publish (items, status, dry_run)Publicar las notas
tracker-download-media (index), tracker-cancelDescargar una previsualización; cancelar

Diagnóstico

ComandoEfecto
statusTodo el estado del reproductor (véase más abajo)
system-infoVersión, sistema, tarjeta gráfica, bibliotecas; sin nombre, sin ruta
dump-thumbnails (output, track)Las miniaturas de la timeline como una hoja PNG
quitCerrar el reproductor de forma limpia

Eventos

El reproductor difunde estas líneas a su cliente, sin que se las pidan:

EventoCampos
play, pause—
frame_changedframe: la posición, en cada fotograma en que cambia (reproducción, arrastre, salto)
export-doneok, cancelled, error, frames_written, output, jobs, seconds, encoder
tracker-connectedok, site, user, reason
tracker-projects, tracker-playlistsok, projects o playlists, reason
tracker-loadedok, items, missing_media, reason
tracker-publish-donepublished, skipped, failed, dry_run
tracker-download-doneindex, ok, path o reason

status

{"cmd": "status"} devuelve todo el estado. Los bloques más útiles: playback (state, currentFrame, startOffset, fps, ab_mode, ab_view, transitioning, los contadores late_frames y lost_frames), color (la corrección de la pista A, canal), viewport (resolución decodificada y original, proxy_idx, retiering, zoom), decode (tiempo de decodificación, too_slow), track_b, ram_fit y playlist (una entrada por clip).

Ejemplos

Abrir el último render y reproducirlo (desde un botón de Nuke, por ejemplo):

client.open_media("D:/renders/SQ010_SH010_COMP_v003/SQ010_SH010_COMP_v003.1001.exr")
client.set_colorspace("ACEScg")
client.play()

Seguir el cabezal de reproducción (para mantener sincronizada una timeline de Maya, por ejemplo):

client.on("frame_changed", lambda e: print("position", e["frame"]))
client.on("play", lambda e: print("playing"))

Exportar dailies y esperar al final:

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"))

Recoger las notas de una revisión:

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"))

Iniciar una sesión de revisión protegida con contraseña:

r = client.session_create(name="SQ010 dailies", password="...")
for link in r["links"]:
    print(link["kind"], link["link"])   # lan, vpn...

Formatos de archivo

La carpeta api contiene los esquemas JSON de los archivos intercambiados: playlist.schema.json (la playlist .bpl, con el bloque x_tracking de identificadores del tracker), notes_payload.schema.json (el export.json de las notas) y export_recipe.schema.json (recetas de exportación), y trabajos de exportación de ejemplo en export_examples/.

Véanse también: Línea de comandos y exportación sin ventana, Integraciones.