DOCUMENTATION DÉVELOPPEUR

API Python et IPC

Piloter Bernard Review depuis un script ou un logiciel du pipeline. Le protocole, le client Python, toutes les commandes par famille, les événements et des exemples complets.

Bernard Review se pilote depuis Python, Maya, Nuke, Houdini, un outil de suivi de production ou tout langage capable d'ouvrir une connexion TCP. Tout ce qu'un artiste fait à la main a sa commande : ouvrir des plans, lire, comparer, étalonner, exporter, lancer une séance, publier des notes. Cette page suffit pour automatiser le lecteur ; la référence exhaustive, champ par champ, est la référence de l'API, en anglais (aussi ouverte par Help > API Documentation).

Le protocole

  • Adresse : 127.0.0.1, port 5556 par défaut. Un lecteur lancé avec --ipc-port N écoute sur N : c'est ainsi que deux lecteurs tournent sur la même machine.
  • Format : JSON Lines. Chaque requête est un objet JSON sur une ligne, terminé par \n, avec un champ "cmd" : {"cmd": "seek", "frame": 24}.
  • Une réponse par requête, dans l'ordre d'envoi, en général en quelques millisecondes : {"status": "ok", "cmd": "seek", ...} ou {"status": "error", "cmd": "seek", "reason": "..."}. Une erreur porte toujours une raison en clair et n'attend jamais l'expiration du délai. Il n'y a pas d'identifiant de requête : on associe une réponse à sa requête par son "cmd".
  • Les événements du lecteur ({"event": ...}) arrivent sur la même connexion, mêlés aux réponses (voir plus bas).
  • Un client à la fois. Une deuxième connexion attend que la première se ferme.
  • Local seulement. Le port écoute sur la boucle locale. Une connexion qui ressemble à une requête de navigateur (une ligne HTTP, un en-tête Host:) est fermée sans rien exécuter : une page web ne peut pas piloter le lecteur. Une ligne fait au plus 16 Mio.
  • Aucun secret ne passe par ce port pour les trackers : une requête qui contient un mot de passe, une clé ou un jeton de tracker est refusée.

Pour essayer sans écrire de code : Window > Console (Ctrl+Maj+C) envoie les mêmes commandes depuis le lecteur, avec complétion par Tab : status, seek {"frame": 24}, ou la forme JSON complète. Elle demande confirmation avant les commandes qui écrivent des fichiers, publient ou ferment le lecteur.

La Console avec une commande seek et sa réponse, puis le début de la réponse à status.

Le client Python

bernard_api.py emballe le protocole dans une classe, BernardClient, avec une méthode par commande. Il est installé à côté du lecteur, dans le dossier api :

SystèmeEmplacement
WindowsC:\Program Files\Bernard Review\bin\api\bernard_api.py
Linux (RPM)/usr/share/bernardplayer/api/bernard_api.py
Linux (archive .sh)<dossier d'installation>/share/bernardplayer/api/bernard_api.py

Il n'a besoin que de la bibliothèque standard 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 ne répond pas sur le port 5556")

reply = client.open_media("D:/shots/SQ010_SH010_ANIM_v002.mov")
if reply is None or reply.get("status") == "error":
    print("refusé :", reply and reply.get("reason"))
else:
    client.play()
  • request(dict) envoie une commande et attend sa réponse (un dict), erreurs comprises : elle ne lève pas d'exception pour un refus du lecteur, et renvoie None en cas d'expiration ou de connexion perdue.
  • send_command(dict) envoie sans attendre.
  • Les méthodes nommées (play(), seek(), set_exposure(), export()...) appellent l'une ou l'autre ; celles qui renvoient des données passent par request().
  • on("frame_changed", fonction) abonne une fonction à un événement ; un fil de fond lit la connexion.

Sans le client, quelques lignes suffisent :

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":      # on saute les événements
            print(msg["playback"]["currentFrame"]); break

Ce qu'il faut savoir avant d'écrire un script

  • Les numéros d'image. seek, set-in, set-out et l'option --frame prennent la position dans le plan comptée à partir de 0, pas le numéro affiché sur la règle. Sur un plan qui commence à 1001, l'image affichée 1010 est la position 9. status donne la position (playback.currentFrame) et le numéro de départ (playback.startOffset).
  • Ce qui est asynchrone. open répond avant que le plan soit sondé : status.playback.transitioning reste true jusqu'à ce que le plan soit à l'écran. export met un travail en file : suivez-le avec export-status ou l'événement export-done. export-notes écrit ses fichiers en arrière-plan. Après set-proxy, attendez que status.viewport.retiering repasse à false.
  • Un profil neuf pose la question du premier lancement dans une fenêtre modale : envoyez d'abord {"cmd": "set-ui-level", "value": "complete"}.
  • quit répond, puis ferme le lecteur proprement, sans demander s'il faut enregistrer : envoyez save-playlist ou export-notes avant si la revue compte.
  • Plusieurs requêtes du même nom en parallèle ne se distinguent pas : envoyez-les l'une après l'autre.

Les commandes, par famille

Les 115 commandes du lecteur. Les champs entre parenthèses sont les principaux ; track vaut "A" (par défaut) ou "B".

Lecture et plage

CommandeEffet
play, pause, reverse-playLire, mettre en pause, lire à l'envers
seek (frame)Aller à une position (à partir de 0)
step-frame (delta)Avancer ou reculer de delta images
toggle-loopBoucle de la plage
set-playlist-playback (loop_mode 0, 1 ou 2, dont_wait_incomplete_shots)Boucle désactivée, sur le plan ou sur la playlist
set-in, set-out (frame, facultatif)Points d'entrée et de sortie ; sans frame, la tête de lecture
clear-in-out, set-in-out-lock (value)Effacer la plage ; interdire à la souris de la déplacer
set-fps (value), set-start (value)Cadence ; numéro de la première image
set-volume (value 0 à 1), set-mute (value), toggle-muteSon

Plans et playlist

CommandeEffet
open ou load (path)Ouvrir un fichier ou une séquence sur la piste A, en l'ajoutant à la playlist
load-playlist (path)Charger une playlist .bpl, .otio, .csv, .json ou .edl
save-playlist (path)Écrire la playlist en .bpl (notes, statuts, étalonnage, dessins)
playlist-add (path), playlist-play (index), playlist-remove (index), playlist-move (from, to), playlist-clearGérer la playlist (index à partir de 0)
drop (paths, at : track_a, track_b ou viewport_b)Comme un dépôt de fichiers depuis l'explorateur

Comparaison et versions

CommandeEffet
set-ab-mode (value), toggle-abMode A/B
set-track-b (path)Mettre un fichier sur la piste B
set-ab-view (value : a, wipe, b), ab-flipA seul, volet, B seul ; basculer A/B
set-wipe (position 0 à 1, angle en degrés)Position et angle du volet
cycle-b (direction : prev, next)Version précédente ou suivante sur B
pin-track-b (value), set-b-version-preload (value)Épingler B ; précharger les versions voisines
set-ab-label-mode (interaction, always, never), set-metadata-track (a, b, ab)Lettres A/B ; piste de l'onglet Metadata
build-matrix (sequence, id, shots), get-matrixRemplir et lire le tableau des versions (voir Intégrations)

Couleur

CommandeEffet
set-exposure, set-gamma (value, track)Exposition (en diaphs), gamma
set-white-balance (temp, tint de -1 à 1, track), set-offset (value : [r, g, b], track)Balance des blancs, offset
set-colorspace (value)Espace d'entrée de la piste A : ACEScg, sRGB, AP0, AdobeRGB, ProPhoto, Rec709, LogC3, LogC4, ou Auto
set-channel (value : RGBA, R, G, B, A, L ; track)Canal affiché
set-stage (stage, on, track)Couper ou rétablir une étape (exposure, levels, curves, gamma...)
set-curve (channel : master, r, g, b ; points ou reset)Courbes, points [x, y] sur l'axe ACEScct
set-hue-range (range, hue, saturation, lightness)Plages de teintes
color-panel (target, before_after, picker, levels_auto, preset_save, preset_apply...)Panneau couleur ; sans champ, le lit
scopes (open, kind)Scopes et leurs dernières mesures (histogramme, écrêtage)
set-layer (track_idx, layer_idx), layer-info (track)Passe d'un EXR multicouche

Viewer, interface et fenêtres

CommandeEffet
zoom (value, 1 = un pixel source par pixel écran), pan (x, y), fit, flipCadrage
set-fullscreen (value), set-window-size (width, height), set-ui-scale (percent)Fenêtre principale
set-theme (dark, light, neon, system ; ou sombre, clair, systeme), set-ui-level (essential, complete)Affichage et niveau d'interface
reset-layout, new-window (view), close-window (name ou all), windowsDisposition et copies de panneaux
contact-sheet (open, mode, card_w...)Planche contact
set-tool (tool : pen, text, arrow, rect, laser, eraser, pipette, select)Outil de dessin
debug-mouse (x, y, down, alt, release)Souris simulée, pour les tests d'interface

Notes, captures et export

CommandeEffet
export-notes (output_dir)Écrire export.json et export.html sans aucune fenêtre
screenshot (output, frame, annotations)Une image PNG du plan de la piste A, étalonnée comme à l'écran
export (output, preset, source, playlist, format, codec, color, burn_in, annotations, watermark, recipient...)Exporter des images ou un film ; mis en file
export-status, export-cancel, export-presetsSuivre, annuler, lister les préréglages
export-recipe (action : list ou run ; name, file ou recipe ; clips, recipient)Recettes d'export

Mémoire et décodage

CommandeEffet
set-proxy (proxy_idx : 0 = 1/1, 1 = 1/2, 2 = 1/4, 3 = 1/8, 4 = Smart RAM-Fit)Résolution de décodage du plan affiché
set-slow-decode-tier (auto, off)Quand le décodage ne suit pas
set-gpu-decode (value)Décodage GPU de NOVA (bêta) : activer, désactiver ou lire l'état
set-gpu-yuv (value)Envoi YUV au GPU des films (bêta) : activer, désactiver ou lire l'état
set-gpu-video-decode (value)Décodage vidéo par la carte graphique (bêta) : activer, désactiver ou lire l'état
set-gpu-prores (value)Décodage ProRes par le GPU (bêta) : activer, désactiver ou lire l'état
set-ram-limit-gb, set-vram-ring-limit-gb (value ; 0 = Auto pour la VRAM)Budgets mémoire
set-hardware-decode (value)Décodage matériel
ram-fit-apply, precache-playlist (value), full-quality (value), cache-clip-frames (clip_id)Smart RAM-Fit, préchargement
ram-info (frames)Occupation de la mémoire, plan par plan
cache-info, cache-purge (scope)Cache de compression : présent, mais encore vide dans cette version

Séances de revue

CommandeEffet
session-create (name, user_name, password, reach : network ou this_computer)Héberger ; la réponse donne les liens
session-join (address, user_name, password), session-leaveRejoindre, quitter
session-statusTout l'état de la séance : participants, pilote, voix...
session-pass-baton (participant_id), session-set-sync (locked)Passer la main ; Local Review
chat-send (text), chat-log (last)Chat
laser (x, y, active), laser-statusPointeur laser
voice-test (seconds)Jouer une tonalité dans le haut-parleur de la voix
stream-enable (on, width, height), stream-statusDiffusion aux invités web

Trackers (sans aucun secret dans les requêtes)

CommandeEffet
tracker-sitesLes sites de trackers.json
tracker-connect (site), tracker-disconnect (site, forget)Connexion
tracker-projects, tracker-playlists (project_id)Parcourir
tracker-load-playlist (playlist_id, mode : replace ou append)Charger une playlist
tracker-publish (items, status, dry_run)Publier les notes
tracker-download-media (index), tracker-cancelTélécharger un aperçu ; annuler

Diagnostic

CommandeEffet
statusTout l'état du lecteur (voir plus bas)
system-infoVersion, système, carte graphique, bibliothèques ; sans nom ni chemin
dump-thumbnails (output, track)Les vignettes de la timeline dans une planche PNG
quitFermer le lecteur proprement

Les événements

Le lecteur diffuse ces lignes à son client, sans qu'il les demande :

ÉvénementChamps
play, pause—
frame_changedframe : la position, à chaque image où elle change (lecture, glisser, saut)
export-doneok, cancelled, error, frames_written, output, jobs, seconds, encoder
tracker-connectedok, site, user, reason
tracker-projects, tracker-playlistsok, projects ou playlists, reason
tracker-loadedok, items, missing_media, reason
tracker-publish-donepublished, skipped, failed, dry_run
tracker-download-doneindex, ok, path ou reason

status

{"cmd": "status"} renvoie l'état complet. Les blocs les plus utiles : playback (state, currentFrame, startOffset, fps, ab_mode, ab_view, transitioning, les compteurs late_frames et lost_frames), color (étalonnage de la piste A, canal), viewport (résolution décodée et d'origine, proxy_idx, retiering, zoom), decode (temps de décodage, too_slow), track_b, ram_fit et playlist (un élément par plan).

Exemples

Ouvrir le dernier rendu et le lire (par exemple depuis un bouton de Nuke) :

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

Suivre la tête de lecture (pour synchroniser une timeline Maya, par exemple) :

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

Exporter des dailies et attendre la fin :

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

Récupérer les notes d'une revue :

import json, os, time
out = "D:/review/SQ010_notes"
client.export_notes(out)
time.sleep(2)  # l'écriture se fait en arrière-plan
notes = json.load(open(os.path.join(out, "export.json"), encoding="utf-8"))

Lancer une séance de revue protégée :

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

Formats de fichiers

Le dossier api contient les schémas JSON des fichiers échangés : playlist.schema.json (la playlist .bpl, avec le bloc x_tracking des identifiants de tracker), notes_payload.schema.json (le export.json des notes) et export_recipe.schema.json (les recettes d'export), ainsi que des exemples de travaux d'export dans export_examples/.

Voir aussi : Ligne de commande et export sans fenêtre, Intégrations.