Introduzione allo scripting OBS

OBS può essere esteso con script Python e Lua. Questo insieme di pagine spiega le basi per iniziare e descrive come implementare le funzioni comuni.

Finestra di gestione degli script

Gli script vengono gestiti dall'utente tramite la finestra di dialogo Script , visualizzata tramite la voce di menu Strumenti> Script :

Finestra principale degli script

Sul lato sinistro viene visualizzato un elenco di script attualmente aggiunti a OBS (qui due script distribuiti con OBS). Sul lato destro, se presenti, vengono mostrate la descrizione e le proprietà modificabili dello script. È possibile aggiungere uno script facendo clic su + e selezionando il relativo file Python o Lua, rimosso con -. Utilizzare il pulsante 🗘 per ricaricare gli script e il pulsante Impostazioni predefinite per ripristinare i valori delle proprietà modificabili ai valori predefiniti.

Per gli script Python, una distribuzione decente di Python deve essere installata dall'utente e il percorso di installazione di Python deve essere impostato nella scheda Impostazioni Python . Fare riferimento alla documentazione dello scripting OBS per la versione supportata di Python (attualmente Python 3.6). A seconda dell'installazione di Python, individuare il percorso di installazione può essere difficile, ad esempio su Windows 10 con Python installato da Microsoft Store, il percorso di installazione si trova in [UserFolder]\AppData\Local\Programs\Python\Python36.

Ecosistema OBS

Lo scripting è un modo per aggiungere funzionalità a OBS ma non è l'unico. Avere una panoramica del contesto è importante prima di entrare nei dettagli. Di seguito è riportato un elenco non esaustivo di metodi che è possibile utilizzare per sviluppare nuove funzioni che interagiscono con OBS:

  • I plugin sono tipicamente implementati in C / C ++ e compilati in librerie dinamiche che vengono scoperte e caricate in fase di esecuzione da OBS. I principali vantaggi dei plugin sono ovviamente le prestazioni e l'accesso grezzo a tutte le funzioni e librerie di OBS. Uno svantaggio significativo è la necessità di configurare un ambiente di compilazione OBS e di gestire le versioni successive di OBS se è necessaria la ricompilazione. Inoltre, se è prevista un'ampia distribuzione, è necessario considerare la compilazione e l'installazione per diverse piattaforme.
  • Gli script sono scritti in Lua o Python e vengono interpretati o compilati al volo in fase di esecuzione. Gli script sono per lo più indipendenti dalla piattaforma e di solito non sono influenzati da lievi modifiche delle strutture dei dati OBS. Hanno accesso a grandi porzioni dell'API C OBS. I vantaggi evidenti sono lo sviluppo e la manutenzione semplificati mentre supportano molte funzionalità dei plugin. Lo svantaggio è una prestazione inferiore, che non è un problema nella maggior parte dei casi.
  • I dock e le fonti del browser (per Windows e macOS) possono utilizzare un'API Javascript per reagire agli eventi in OBS e recuperare le informazioni di base. Possono essere ospitati su un server web o localmente e supportano ciò che Chromium supporta (inclusi HTML5, WebGL, ecc.). In genere vengono utilizzati come fonti per le sovrapposizioni che reagiscono agli eventi.
  • WebSocket può essere utilizzato per controllare in remoto OBS tramite un'interfaccia di rete . Diverse librerie supportano il protocollo per applicazioni personalizzate (C #, Javascript, Python, Java, ..).
  • Numerosi plugin e script possono fornire il comportamento desiderato senza sviluppo. Ad esempio, StreamFX supporta shader personalizzati con parametri di input personalizzabili per filtri, sorgenti o effetti video di transizione.

Confronto tra Python e Lua per lo scripting in OBS

Lua è di gran lunga meno popolare e meno potente di Python, ma è un po 'più semplice (apposta, per ridurre la complessità e l'ingombro nell'eseguibile di incorporamento) e meglio integrato in OBS (a partire dalla v26.1):

Criteri Pitone Lua
Utilizzo generale Ampio utilizzo per tutto, libreria standard completa , ecc Utilizzo scarso principalmente come estensione di scripting incorporata (ad esempio in Wireshark , VLC , RPM , ecc.), Libreria standard scadente (utilizzare l'API OBS o FFI per colmare le lacune)
Moduli aggiuntivi Supportato ad esempio con pip Supportato per i moduli Lua puri, probabilmente possibile ma complesso per i moduli con binario
Interprete Non incorporato Completamente integrato, basato su LuaJIT
Moduli libobs supportati Nessuna Fonti che utilizzano source_info

Documentazione API

OBS ha un'enorme API di funzioni C e strutture dati. Le funzionalità API specifiche per gli script sono descritte nella documentazione relativa agli script di OBS . Il resto dell'API è documentato solo nella versione C originale, non c'è documentazione delle funzioni e delle strutture dati viste finora dall'ambiente di scripting.

Queste risorse possono essere utili (sentiti libero di aggiungere qualcosa):

Iniziare

Un semplice editor di testo è l'unica cosa di cui hai bisogno per iniziare, ma preferisci l'IDE di tua scelta per un editing più comodo. Finora non esiste alcun file di supporto ufficiale per funzionalità come Intellisense.

In questo Wiki vengono proposti due tutorial:

  • Inizia con il tutorial Source Shake che mostra come animare una fonte visualizzata in una scena con un tasto di scelta rapida e proprietà personalizzabili, in Python e Lua
  • Il tutorial Filtro mezzitoni è un esempio di filtro video basato su shader in Lua

Altre risorse del tutorial (sentiti libero di aggiungere qualcosa):

Binding

Non esiste un forte livello di protezione o controllo della coerenza tra lo scripting e le funzioni binarie. Le funzioni C dell'API OBS sono associate all'ambiente di scripting tramite funzioni wrapper scritte in C e compilate nelle librerie OBS.

In genere, quando una funzione Python / Lua viene chiamata in uno script, l'interprete chiama la relativa funzione wrapper C che implementa questi 3 passaggi:

  1. Convalida dei dati forniti come argomenti alla funzione di script e conversione di questi dati dai tipi Python / Lua ai tipi C
  2. Chiamata alla funzione C originale dell'API
  3. Conversione dei dati restituiti dalla funzione C dai tipi C ai tipi Python / Lua

Esistono anche funzioni wrapper per "getter" e "setters", al fine di accedere ai membri delle strutture dati OBS, sempre con la conversione dei dati tra tipi C e tipi Python / Lua.

Quasi tutte le funzioni wrapper vengono generate automaticamente da SWIG durante la compilazione OBS, in base alla definizione delle funzioni API in C.Per alcune funzioni e strutture C complesse, per le quali SWIG non genererebbe automaticamente il codice appropriato, le funzioni wrapper vengono scritte manualmente. Questo è il caso delle funzioni relative al frontend source_infoe delle funzioni con argomenti di callback (vedere la sezione altre differenze dall'API C ).

: avviso: anche se la maggior parte delle funzioni sono utilizzabili come previsto (specialmente quelle riprogettate specificamente per lo scripting), alcune funzioni con wrapper scritti da SWIG non possono essere utilizzate direttamente per lo scripting fino ad ora, perché SWIG non può interpretare correttamente i tipi di dati degli argomenti o restituire i valori forniti nella definizione C. In genere, con i valori passati per riferimento o buffer, i puntatori C ei tipi di puntatore-puntatore sono intrinsecamente ambigui.

Ciclo di vita dello script

Uno script deve definire alcune funzioni di script globali chiamate dall'ambiente di scripting in diverse fasi del ciclo di vita dello script e in diverse fasi di esecuzione di OBS. I seguenti passaggi vengono eseguiti ovunque siano implementate le funzioni di script globale correlate.

Funzioni di script globali chiamate all'avvio di OBS

Quando uno script è stato precedentemente aggiunto a OBS, all'avvio:

  1. Il contenuto del file di script viene letto e interpretato in un nuovo contesto di esecuzione dello script (le funzioni di script globali sono definite durante questa prima esecuzione)
  2. script_defaults(settings) viene chiamato per inizializzare i valori predefiniti nelle impostazioni dei dati
  3. script_description()viene chiamato per recuperare una stringa di descrizione da visualizzare nella finestra Scripts (con formattazione in stile Qt : bulb :)
  4. script_load(settings) viene chiamato per un'inizializzazione una tantum, possibilmente utilizzando i valori delle impostazioni dei dati (in genere per configurare i gestori di segnali)
  5. script_update(settings) viene chiamata una prima volta per le inizializzazioni a seconda dei valori delle impostazioni dei dati (questa funzione verrà richiamata nuovamente dopo ogni modifica del valore nelle impostazioni dei dati, vedere di seguito)

Si prega di notare che:

  • I valori delle impostazioni dei dati disponibili settingsdurante OB di avviamento riflettono lo stato salvato alla precedente chiusura OBS (proprietà modificate dall'utente), e sono già impostati in settingsquando script_defaults, script_loade script_updatesono chiamati
  • Poiché OBS non memorizza i valori delle proprietà che non sono state modificate dall'utente, ovvero le proprietà sono ancora impostate sui valori predefiniti, tali valori non sono disponibili settingsquando script_defaultsviene chiamato all'avvio di OBS (e sono disponibili come impostati in script_defaultsseguito in script_loade script_update)
  • Durante l'avvio di OBS, i passaggi da 1 a 5 vengono eseguiti prima di caricare le scene e le fonti nel frontend (prima che OBS_FRONTEND_EVENT_FINISHED_LOADINGvenga emesso). Ciò è particolarmente importante script_updatese si cercano fonti o scene.

Controlla come OBS salva le proprietà nel file di configurazione JSON dell'utente (in [UserFolder]\AppData\Roaming\obs-studio\basic\scenesWindows) per capire meglio cosa sta succedendo.

Funzione di script globale chiamata ogni frame

Durante l'esecuzione di OBS, una volta inizializzato uno script, script_tick(seconds)viene chiamato ogni frame renderizzato ( secondsè il tempo in secondi trascorso dal frame precedente). Considera l'idea di utilizzare un timer invece di un test ricorrente, script_tickse possibile.

: avviso: fai molta attenzione con il codice script_tick, OBS potrebbe non rispondere rapidamente se qualche errore o testo viene registrato in ogni frame.

Funzioni di script globali chiamate alla chiusura di OBS

Alla chiusura di OBS vengono chiamate due funzioni di script globali:

  1. script_save(settings) viene chiamato appena prima di salvare le impostazioni dei dati in modo persistente
  2. script_unload() viene chiamato appena prima della distruzione del contesto di esecuzione dello script

Le impostazioni dei dati vengono salvate automaticamente alla chiusura di OBS, non è necessario che lo script richiami alcuna funzione per salvare le impostazioni dei dati (e non è necessario implementare script_savescript_unloadattivare OBS per salvare i dati impostati da uno script).

Funzioni di script globali per proprietà modificabili

Una volta completato l'avvio di OBS, script_properties()viene richiamato da OBS se lo script è selezionato nella finestra Scripts (selezionando un altro script si richiamerebbe sempre la relativa script_propertiesfunzione).

La funzione deve restituire un obs_properties_toggetto creato utilizzando obs_properties_createe riempito con elementi della GUI attraverso le obs_properties_add_*funzioni. L'oggetto verrà rilasciato da OBS quando necessario.

È possibile impostare una funzione di callback per ciascuna proprietà utilizzando obs_property_set_modified_callback.

Quando il valore di una proprietà viene modificato, la sequenza è:

  1. script_update(settings) viene chiamato (per inizializzazioni a seconda dei valori delle impostazioni dei dati)
  2. Viene chiamato il callback della proprietà modificata

Si prega di notare che:

  • : bulb: la descrizione di una proprietà supporta la formattazione in stile Qt
  • : bulb: una funzione di callback impostata su una proprietà con obs_property_set_modified_callbackdeve restituire true per attivare l'aggiornamento del widget delle proprietà (nessuna nuova chiamata a script_properties)
  • Se un'altra proprietà o impostazione dei dati viene modificata per script, ad esempio in script_update, il suo callback non viene attivato automaticamente, utilizzare obs_properties_apply_settingsper attivare tutti i callback (ad esempio in script_updatecon un oggetto proprietà salvato in una variabile globale in script_properties)

Le funzioni di script globali chiamano la sequenza per altre operazioni

Le operazioni di gestione disponibili nella finestra Script attivano sequenze più complesse (descritte in questa sezione come in OBS v26.1, il comportamento potrebbe cambiare in futuro).

Aggiunta di uno script:

  • Passaggi di inizializzazione come all'avvio di OBS tranne per il fatto che i valori delle impostazioni dei dati non sono disponibili:

    1. Prima esecuzione dello script
    2. script_defaults
    3. script_description
    4. script_load
    5. script_update
  • Quindi, quando lo script viene selezionato nella finestra Script , le proprietà vengono inizializzate e visualizzate:

    1. script_properties
    2. Chiama tutti i "callback modificati", per tutte le proprietà (con le impostazioni dei dati ancora non disponibili)
    3. script_properties ancora
    4. script_update con le impostazioni dei dati disponibili
    5. Chiamata ai "callback modificati" di proprietà effettivamente modificate nei passaggi precedenti

: attenzione: la sequenza completa può portare a incongruenze se non gestita con attenzione, perché le stesse funzioni vengono chiamate più volte, inclusi i callback delle proprietà al punto 7, mentre le impostazioni dei dati non sono disponibili (crediti all'eucratismo per aver sottolineato questo comportamento).

La rimozione di uno script attiva solo una chiamata a script_unload( not script_save ).

Il ripristino delle impostazioni predefinite inizia con una chiamata a script_updateseguita dagli stessi passaggi della rimozione e quindi dell'aggiunta di uno script (impostazioni dei dati non disponibili).

Ricaricare uno script equivale a rimuovere e quindi aggiungere nuovamente uno script, tranne per il fatto che i valori delle impostazioni dei dati sono disponibili durante l'intera sequenza.

Risoluzione dei problemi

È normale che si verifichino arresti anomali di OBS o comportamenti imprevisti durante lo sviluppo. Alcuni suggerimenti (sentiti libero di aggiungere il tuo!):

  • Gli script vengono caricati molto presto all'avvio di OBS, prima che appaia la GUI. A seconda di ciò che lo script fa all'inizio, può portare a un tempo di inizio molto lungo (ad esempio, compilazione di shader con loop srotolati).
  • Se OBS si arresta in modo anomalo all'avvio a causa di uno script o di parametri errati forniti a uno script, non sarà possibile disattivare lo script difettoso nella finestra di dialogo Script . Per ripristinare: rinominare lo script, avviare OBS, rimuovere lo script difettoso dall'elenco degli script allegati, ecc.
  • OBS tenderà a mantenere qualsiasi proprietà definita / modificata nel file di configurazione JSON dell'utente, anche se la proprietà correlata non esiste più in una versione successiva dello script. Rimuovere uno script e quindi aggiungerlo di nuovo (e reimpostare le proprietà correlate) ripulirà tali proprietà fantasma.
  • OBS potrebbe bloccarsi quando vengono registrati troppi dati contemporaneamente o potrebbe non rispondere dopo un paio di minuti. Ciò è particolarmente vero quando i dati vengono registrati in ogni frame, ad esempio quando si verifica un errore ricorrente in script_tick. Potrebbe essere necessario chiudere la finestra OBS o addirittura terminare il processo per il ripristino.
  • Molte funzioni in OBS allocano i dati che devono essere rilasciati. Questo è il significato dell'avviso nella documentazione: rilascia / distruggi oggetti a cui fai riferimento o che crei tramite l'API . Ad esempio, una chiamata a obs_get_current_scenedeve essere seguita da una chiamata a obs_source_releaseOBS altrimenti potrebbe bloccarsi all'uscita (con "Liberazione dei dati di contesto OBS" come ultima voce di registro). La necessità di rilasciare oggetti non è sempre documentata. Come regola pratica, se la documentazione API indica Resi: un nuovo riferimento ... o Restituzioni: un riferimento incrementato ... allora è probabilmente necessaria una chiamata a una funzione di rilascio (crediti a J. Buchanan per questa utile sintesi).
  • Il parser degli effetti manca spesso parentesi sbilanciate, senza alcun registro (crediti a skeletonbow per questa osservazione generale). Si consiglia di utilizzare un IDE in grado di rilevare tali problemi in HLSL ( .hlslpotrebbe essere utile utilizzare l'estensione sul nome del file dell'effetto).