Hello everyone, in this part of the tutorial we will consider:
filters, scenes, scene objects, Frontend API, creating functional filters, and more ...
The first part can be found at this link.
Quick reference for this part
Source - Sources are used to render audio / video, for example: capture of a camera, game, sound. Using sources, you can create filters, transitions
Filter - Source that complements other sources
-
— , : , /, , / ..
Frontend API — OBS Studio, :
- , /
- / /
, obs_source_get_unversioned_id
compressor_filter | |
expander_filter | |
gain_filter | |
invert_polarity_filter | |
limiter_filter | |
noise_gate_filter | |
noise_suppress_filter | |
VST 2.x | vst_filter |
() | async_delay_filter |
chroma_key_filter | |
color_filter | |
color_key_filter | |
crop_filter | |
/ | mask_filter |
luma_key_filter | |
gpu_delay | |
/ | scale_filter |
scroll_filter | |
sharpness_filter |
: 1 100.
"" - , . , OBS:
>
>
, ~/basic>scenes>_.json
color_filter
color_key_filter
( ).
settings
opacity
.
, —
function add_filter_to_source(random_n)
source = obs.obs_get_source_by_name(source_name)
opacity
settings = obs.obs_data_create()
obs.obs_data_set_int(settings, "opacity",random_n)
,
_color_filter = obs.obs_source_get_filter_by_name(source,"opacity_random")
if _color_filter == nil then -- if not exists
_color_filter = obs.obs_source_create_private( "color_filter", "opacity_random", settings)
obs.obs_source_filter_add(source, _color_filter)
end
obs.obs_source_update(_color_filter,settings)
obs.obs_source_release(source)
obs.obs_data_release(settings)
obs.obs_source_release(_color_filter)
end
function htk_1_cb(pressed)
if pressed then
n = math.random(1,100)
add_filter_to_source(n)
end
end
local obs = obslua
source_name = ''
function htk_1_cb(pressed)
if pressed then
n = math.random(1,100)
add_filter_to_source(n)
end
end
function add_filter_to_source(random_n)
source = obs.obs_get_source_by_name(source_name)
settings = obs.obs_data_create()
obs.obs_data_set_int(settings, "opacity",random_n)
_color_filter = obs.obs_source_get_filter_by_name(source,"opacity_random")
if _color_filter == nil then -- if not exists
_color_filter = obs.obs_source_create_private( "color_filter", "opacity_random", settings)
obs.obs_source_filter_add(source, _color_filter)
end
obs.obs_source_update(_color_filter,settings)
obs.obs_source_release(source)
obs.obs_data_release(settings)
obs.obs_source_release(_color_filter)
end
function script_properties()
-- source https://raw.githubusercontent.com/insin/obs-bounce/master/bounce.lua
local props = obs.obs_properties_create()
local source = obs.obs_properties_add_list(
props,
'source',
'Source:',
obs.OBS_COMBO_TYPE_EDITABLE,
obs.OBS_COMBO_FORMAT_STRING)
for _, name in ipairs(get_source_names()) do
obs.obs_property_list_add_string(source, name, name)
end
return props
end
function script_update(settings)
source_name = obs.obs_data_get_string(settings, 'source')
end
--- get a list of source names, sorted alphabetically
function get_source_names()
local sources = obs.obs_enum_sources()
local source_names = {}
if sources then
for _, source in ipairs(sources) do
-- exclude Desktop Audio and Mic/Aux by their capabilities
local capability_flags = obs.obs_source_get_output_flags(source)
if bit.band(capability_flags, obs.OBS_SOURCE_DO_NOT_SELF_MONITOR) == 0 and
capability_flags ~= bit.bor(obs.OBS_SOURCE_AUDIO, obs.OBS_SOURCE_DO_NOT_DUPLICATE) then
table.insert(source_names, obs.obs_source_get_name(source))
end
end
end
obs.source_list_release(sources)
table.sort(source_names, function(a, b)
return string.lower(a) < string.lower(b)
end)
return source_names
end
key_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ]}'
json_s = key_1
default_hotkeys = {
{id='htk_1',des=' 1 ',callback=htk_1_cb},
}
function script_load(settings)
s = obs.obs_data_create_from_json(json_s)
for _,v in pairs(default_hotkeys) do
a = obs.obs_data_get_array(s,v.id)
h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)
obs.obs_hotkey_load(h,a)
obs.obs_data_array_release(a)
end
obs.obs_data_release(s)
end
obs_source_enum_filters
, obspython
,
.
function check()
source = obs.obs_get_source_by_name(source_name)
result = obs.obs_source_enum_filters(source)
for k,v in pairs(result) do
name = obs.obs_source_get_name(v)
print('name'.. name)
end
obs.source_list_release(result)
obs.obs_source_release(source)
end
.
function on_event(event)
if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED
then obs_play_sound_release_source()
end
end
, : alert.mp3
, obs_source_set_monitoring_type
.
function play_sound()
mediaSource = obs.obs_source_create_private("ffmpeg_source", "Global Media Source", nil)
local s = obs.obs_data_create()
obs.obs_data_set_string(s, "local_file",script_path() .. "alert.mp3")
obs.obs_source_update(mediaSource,s)
obs.obs_source_set_monitoring_type(mediaSource,obs.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)
obs.obs_data_release(s)
obs.obs_set_output_source(outputIndex, mediaSource)
return mediaSource
end
function obs_play_sound_release_source()
r = play_sound()
obs.obs_source_release(r)
end
local obs = obslua
mediaSource = nil -- Null pointer
outputIndex = 63 -- Last index
function play_sound()
mediaSource = obs.obs_source_create_private("ffmpeg_source", "Global Media Source", nil)
local s = obs.obs_data_create()
obs.obs_data_set_string(s, "local_file",script_path() .. "alert.mp3")
obs.obs_source_update(mediaSource,s)
obs.obs_source_set_monitoring_type(mediaSource,obs.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT)
obs.obs_data_release(s)
obs.obs_set_output_source(outputIndex, mediaSource)
return mediaSource
end
function obs_play_sound_release_source()
r = play_sound()
obs.obs_source_release(r)
end
function on_event(event)
if event == obs.OBS_FRONTEND_EVENT_SCENE_CHANGED
then obs_play_sound_release_source()
end
end
function script_load(settings)
obs.obs_frontend_add_event_callback(on_event)
end
function script_unload()
obs.obs_set_output_source(outputIndex, nil)
end
, "a" — ( ) "content", "w" — .
io.output(io.open(script_path() .. "out.txt","a"))
io.write("content")
io.close()
print(os.date("%c"))
--
obs_sceneitem_get_source
—obs_scene_from_source
—obs_scene_find_source
—obs_frontend_get_scenes
— ,source_list_release
obs_frontend_get_current_scene
—obs_scene_enum_items
— ,sceneitem_list_release
: ( ).
function toggle_source()
scenes = obs.obs_frontend_get_scenes()
for _,scene in pairs(scenes) do
scene_source = obs.obs_scene_from_source(scene)
items = obs.obs_scene_enum_items(scene_source)
...
, source_name
boolean
.
...
for _,scene_item in pairs(items) do
_source = obs.obs_sceneitem_get_source(scene_item)
_name = obs.obs_source_get_name(_source)
if _name == source_name then
boolean = not boolean
obs.obs_sceneitem_set_visible(scene_item, boolean)
end
end
...
local obs = obslua
source_name = ''
boolean = true
function htk_1_cb(pressed)
if pressed then
toggle_source()
end
end
function toggle_source()
scenes = obs.obs_frontend_get_scenes()
for _,scene in pairs(scenes) do
scene_source = obs.obs_scene_from_source(scene)
items = obs.obs_scene_enum_items(scene_source)
for _,scene_item in pairs(items) do
_source = obs.obs_sceneitem_get_source(scene_item)
_name = obs.obs_source_get_name(_source)
if _name == source_name then
boolean = not boolean
obs.obs_sceneitem_set_visible(scene_item, boolean)
end
end
obs.sceneitem_list_release(items)
end
obs.source_list_release(scenes)
end
function script_properties()
-- source https://raw.githubusercontent.com/insin/obs-bounce/master/bounce.lua
local props = obs.obs_properties_create()
local source = obs.obs_properties_add_list(
props,
'source',
'Source:',
obs.OBS_COMBO_TYPE_EDITABLE,
obs.OBS_COMBO_FORMAT_STRING)
for _, name in ipairs(get_source_names()) do
obs.obs_property_list_add_string(source, name, name)
end
obs.obs_property_set_long_description(source,"?" )
return props
end
function script_update(settings)
source_name = obs.obs_data_get_string(settings, 'source')
end
--- get a list of source names, sorted alphabetically
function get_source_names()
local sources = obs.obs_enum_sources()
local source_names = {}
if sources then
for _, source in ipairs(sources) do
-- exclude Desktop Audio and Mic/Aux by their capabilities
local capability_flags = obs.obs_source_get_output_flags(source)
if bit.band(capability_flags, obs.OBS_SOURCE_DO_NOT_SELF_MONITOR) == 0 and
capability_flags ~= bit.bor(obs.OBS_SOURCE_AUDIO, obs.OBS_SOURCE_DO_NOT_DUPLICATE) then
table.insert(source_names, obs.obs_source_get_name(source))
end
end
end
obs.source_list_release(sources)
table.sort(source_names, function(a, b)
return string.lower(a) < string.lower(b)
end)
return source_names
end
key_1 = '{"htk_1": [ { "key": "OBS_KEY_1" } ]}'
json_s = key_1
default_hotkeys = {
{id='htk_1',des=' 1 ',callback=htk_1_cb},
}
function script_load(settings)
s = obs.obs_data_create_from_json(json_s)
for _,v in pairs(default_hotkeys) do
a = obs.obs_data_get_array(s,v.id)
h = obs.obs_hotkey_register_frontend(v.id,v.des,v.callback)
obs.obs_hotkey_load(h,a)
obs.obs_data_array_release(a)
end
obs.obs_data_release(s)
end
obslua
obs_register_source
,
( ).
,
. , , .
: , .
, -.
local obs = obslua
local bit = require("bit")
local info = {} -- obs_source_info https://obsproject.com/docs/reference-sources.html
info.id = "uniq_filter_id"
info.type = obs.OBS_SOURCE_TYPE_FILTER
info.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)
info.get_name = function() return 'default filter name' end
,
info.create = function(settings,source)
local filter = {}
filter.context = source
, .
filter.hotkeys = {
htk_stop = "[stop] ",
htk_restart = "[start] ",
}
filter.hotkey_mapping = function(hotkey,data)
if hotkey == "htk_stop" then
print('stop '.. data.srsn .. " : " .. data.filn)
elseif hotkey == "htk_restart" then
print('restart ' .. data.srsn .. " : " .. data.filn)
end
end
filter.hk = {}
for k,v in pairs(filter.hotkeys) do
filter.hk[k] = obs.OBS_INVALID_HOTKEY_ID
end
( . )
return
filter._reg_htk = function()
info.reg_htk(filter,settings)
end
obs.timer_add(filter._reg_htk,100) -- callback to register hotkeys, one time only
,obs_filter_get_parent
. .
info.reg_htk = function(filter,settings) -- register hotkeys after 100 ms since filter was created
local target = obs.obs_filter_get_parent(filter.context)
local srsn = obs.obs_source_get_name(target)
local filn = obs.obs_source_get_name(filter.context)
local data = {srsn = srsn, filn = filn}
for k, v in pairs(filter.hotkeys) do
filter.hk[k] = obs.obs_hotkey_register_frontend(k, v .. srsn .. " : " .. filn, function(pressed)
if pressed then filter.hotkey_mapping(k,data) end end)
local a = obs.obs_data_get_array(settings, k)
obs.obs_hotkey_load(filter.hk[k], a)
obs.obs_data_array_release(a)
end
obs.remove_current_callback()
end
, ""
info.video_render = function(filter, effect)
-- called every frame
local target = obs.obs_filter_get_parent(filter.context)
if target ~= nil then
filter.width = obs.obs_source_get_base_width(target)
filter.height = obs.obs_source_get_base_height(target)
end
obs.obs_source_skip_video_filter(filter.context)
end
info.get_width = function(filter)
return filter.width
end
info.get_height = function(filter)
return filter.height
end
.save , . .
obs.obs_register_source(info)
— ,
info.save = function(filter,settings)
for k, v in pairs(filter.hotkeys) do
local a = obs.obs_hotkey_save(filter.hk[k])
obs.obs_data_set_array(settings, k, a)
obs.obs_data_array_release(a)
end
end
obs.obs_register_source(info)
info.load
— script_load
, ,
. .update
, .get_properties
script_update
, script_properties
.
local obs = obslua
local bit = require("bit")
local info = {} -- obs_source_info https://obsproject.com/docs/reference-sources.html
info.id = "uniq_filter_id"
info.type = obs.OBS_SOURCE_TYPE_FILTER
info.output_flags = bit.bor(obs.OBS_SOURCE_VIDEO)
info.get_name = function() return 'default filter name' end
info.create = function(settings,source)
local filter = {}
filter.context = source
filter.hotkeys = {
htk_stop = "[stop] ",
htk_restart = "[start] ",
}
filter.hotkey_mapping = function(hotkey,data)
if hotkey == "htk_stop" then
print('stop '.. data.srsn .. " : " .. data.filn)
elseif hotkey == "htk_restart" then
print('restart ' .. data.srsn .. " : " .. data.filn)
end
end
filter.hk = {}
for k,v in pairs(filter.hotkeys) do
filter.hk[k] = obs.OBS_INVALID_HOTKEY_ID
end
filter._reg_htk = function()
info.reg_htk(filter,settings)
end
obs.timer_add(filter._reg_htk,100) -- callback to register hotkeys, one time only
return filter
end
info.reg_htk = function(filter,settings) -- register hotkeys after 100 ms since filter was created
local target = obs.obs_filter_get_parent(filter.context)
local srsn = obs.obs_source_get_name(target)
local filn = obs.obs_source_get_name(filter.context)
local data = {srsn = srsn, filn = filn}
for k, v in pairs(filter.hotkeys) do
filter.hk[k] = obs.obs_hotkey_register_frontend(k, v .. srsn .. " : " .. filn, function(pressed)
if pressed then filter.hotkey_mapping(k,data) end end)
local a = obs.obs_data_get_array(settings, k)
obs.obs_hotkey_load(filter.hk[k], a)
obs.obs_data_array_release(a)
end
obs.remove_current_callback()
end
info.video_render = function(filter, effect)
-- called every frame
local target = obs.obs_filter_get_parent(filter.context)
if target ~= nil then
filter.width = obs.obs_source_get_base_width(target)
filter.height = obs.obs_source_get_base_height(target)
end
obs.obs_source_skip_video_filter(filter.context)
end
info.get_width = function(filter)
return filter.width
end
info.get_height = function(filter)
return filter.height
end
--info.load = function(filter,settings) -- restart required
--... same code as in info.reg_htk, but filters will be created from scratch every time
--obs restarts, there is no reason to define it here again becuase hotkeys will be duplicated
--end
info.save = function(filter,settings)
for k, v in pairs(filter.hotkeys) do
local a = obs.obs_hotkey_save(filter.hk[k])
obs.obs_data_set_array(settings, k, a)
obs.obs_data_array_release(a)
end
end
obs.obs_register_source(info)
obspython
OBS Python, Windows 3.6 , Linux (. ),
MacOS Python (26.0.0) .
Lua , ,
. wrapper -.
.:
- , OO, ..
- http://lua-users.org/wiki/LuaVersusPython — Lua Python
, ,
script_tick
( )
logs
,
— : Number of memory leaks: 0
,
. OBS .
3)[] " "
,
( ) (scroll_filter),
/
0 1000 / 50% .
4)[] ""
.
— ( error())
5)[ ] "-"
,
, "",
UI , .
7) [ ] " "
2 .
- DVD
- https://github.com/WiiPlayer2/obs-scripts —
- https://github.com/bfxdev/OBS — ,
- https://github.com/Palakis/obs-websocket — API OBS Studio websocket, OBS