Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate lists for video and audio filters #1126

Open
wants to merge 3 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion js/module.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,12 @@ export interface IInput extends ISource {
sendFocus(focus: boolean): void;
sendKeyClick(eventData: IKeyEvent, keyUp: boolean): void;
setFilterOrder(filter: IFilter, movement: EOrderMovement): void;
setFilterOrder(filter: IFilter, movement: EOrderMovement): void;
setFilterPosition(filter: IFilter, position: number): void;
setVideoFilterPosition(filter: IFilter, position: number): void;
setAudioFilterPosition(filter: IFilter, position: number): void;
readonly filters: IFilter[];
readonly videoFilters: IFilter[];
readonly audioFilters: IFilter[];
readonly width: number;
readonly height: number;
getDuration(): number;
Expand Down
18 changes: 14 additions & 4 deletions js/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,17 +819,27 @@ export interface IInput extends ISource {
setFilterOrder(filter: IFilter, movement: EOrderMovement): void;

/**
* Move a filter up, down, top, or bottom in the filter list.
* Set a filter position in the filter list.
* @param filter - The filter to move within the input source.
* @param movement - The movement to make within the list.
* @param position - The position to make within the list.
*/
setFilterOrder(filter: IFilter, movement: EOrderMovement): void;
setFilterPosition(filter: IFilter, position: number): void;
setVideoFilterPosition(filter: IFilter, position: number): void;
setAudioFilterPosition(filter: IFilter, position: number): void;


/**
* Obtain a list of all filters associated with the input source
*/
readonly filters: IFilter[];
readonly filters: IFilter[];
/**
* Obtain a list of video filters associated with the input source
*/
readonly videoFilters: IFilter[];
/**
* Obtain a list of audio filters associated with the input source
*/
readonly audioFilters: IFilter[];

/**
* Width of the underlying source
Expand Down
2 changes: 1 addition & 1 deletion obs-studio-client/source/cache-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct SourceDataInfo
uint32_t audioMixers = UINT32_MAX;
bool audioMixersChanged = true;

std::vector<uint64_t>* filters = new std::vector<uint64_t>();
std::vector<std::pair<uint64_t, int>>* filters = new std::vector<std::pair<uint64_t, int>>();
bool filtersOrderChanged = true;
};

Expand Down
146 changes: 121 additions & 25 deletions obs-studio-client/source/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ Napi::Object osn::Input::Init(Napi::Env env, Napi::Object exports) {
InstanceMethod("addFilter", &osn::Input::AddFilter),
InstanceMethod("removeFilter", &osn::Input::RemoveFilter),
InstanceMethod("setFilterOrder", &osn::Input::SetFilterOrder),
InstanceMethod("setFilterPosition", &osn::Input::SetFilterPosition),
InstanceMethod("setVideoFilterPosition", &osn::Input::SetVideoFilterPosition),
InstanceMethod("setAudioFilterPosition", &osn::Input::SetAudioFilterPosition),
InstanceMethod("findFilter", &osn::Input::FindFilter),
InstanceMethod("copyFilters", &osn::Input::CopyFilters),

Expand All @@ -61,6 +64,8 @@ Napi::Object osn::Input::Init(Napi::Env env, Napi::Object exports) {
InstanceAccessor("deinterlaceFieldOrder", &osn::Input::GetDeinterlaceFieldOrder, &osn::Input::SetDeinterlaceFieldOrder),
InstanceAccessor("deinterlaceMode", &osn::Input::GetDeinterlaceMode, &osn::Input::SetDeinterlaceMode),
InstanceAccessor("filters", &osn::Input::Filters, nullptr),
InstanceAccessor("videoFilters", &osn::Input::VideoFilters, nullptr),
InstanceAccessor("audioFilters", &osn::Input::AudioFilters, nullptr),
InstanceAccessor("seek", &osn::Input::GetTime, &osn::Input::SetTime),

InstanceAccessor("configurable", &osn::Input::CallIsConfigurable, nullptr),
Expand Down Expand Up @@ -572,20 +577,44 @@ void osn::Input::SetDeinterlaceMode(const Napi::CallbackInfo& info, const Napi::
}

Napi::Value osn::Input::Filters(const Napi::CallbackInfo& info)
{
return GetFilters(info, osn::FilterSubset::All);
}

Napi::Value osn::Input::AudioFilters(const Napi::CallbackInfo& info)
{
return GetFilters(info, osn::FilterSubset::Audio);
}

Napi::Value osn::Input::VideoFilters(const Napi::CallbackInfo& info)
{
return GetFilters(info, osn::FilterSubset::Video);
}

Napi::Value osn::Input::FiltersFromCache(const Napi::CallbackInfo& info, osn::FilterSubset subset, std::vector<std::pair<uint64_t, int>> * filters)
{
Napi::Array array = Napi::Array::New(info.Env());
int index = 0;
for (uint32_t i = 0; i < filters->size(); i++) {
if ((filters->at(i).second == static_cast<int>(osn::FilterSubset::Video) && subset == osn::FilterSubset::Audio)
|| (filters->at(i).second == static_cast<int>(osn::FilterSubset::Audio) && subset == osn::FilterSubset::Video))
continue;
auto instance =
osn::Filter::constructor.New({
Napi::Number::New(info.Env(), filters->at(i).first)
});
array.Set(index, instance);
index++;
}
return array;
}

Napi::Value osn::Input::GetFilters(const Napi::CallbackInfo& info, osn::FilterSubset subset)
{
SourceDataInfo* sdi = CacheManager<SourceDataInfo*>::getInstance().Retrieve(this->sourceId);

if (sdi && !sdi->filtersOrderChanged) {
std::vector<uint64_t>* filters = sdi->filters;
Napi::Array array = Napi::Array::New(info.Env(), int(filters->size()));
for (uint32_t i = 0; i < filters->size(); i++) {
auto instance =
osn::Filter::constructor.New({
Napi::Number::New(info.Env(), filters->at(i))
});
array.Set(i, instance);
}
return array;
return FiltersFromCache(info, subset, sdi->filters);
}

auto conn = GetConnection(info);
Expand All @@ -598,28 +627,35 @@ Napi::Value osn::Input::Filters(const Napi::CallbackInfo& info)
if (!ValidateResponse(info, response))
return info.Env().Undefined();

std::vector<uint64_t>* filters;
Napi::Array array = Napi::Array::New(info.Env());
std::vector<std::pair<uint64_t, int>>* filters;
if (sdi) {
filters = sdi->filters;
filters->clear();
}

Napi::Array array = Napi::Array::New(info.Env(), response.size() - 1);
for (size_t idx = 1; idx < response.size(); idx++) {
auto instance =
osn::Filter::constructor.New({
Napi::Number::New(info.Env(), response[idx].value_union.ui64)
});
array.Set(uint32_t(idx) - 1, instance);

if (sdi)
filters->push_back(response[idx].value_union.ui64);
}
for (size_t idx = 1; idx < response.size(); idx += 2) {
filters->push_back(std::make_pair(response[idx].value_union.ui64, response[idx+1].value_union.i32));
}

if (sdi)
sdi->filtersOrderChanged = false;

return array;
return FiltersFromCache(info, subset, filters);
} else {
int index = 0;
for (size_t idx = 1; idx < response.size(); idx += 2) {
if ((response[idx+1].value_union.i32 == static_cast<int>(osn::FilterSubset::Video) && subset == osn::FilterSubset::Audio)
|| (response[idx+1].value_union.i32 == static_cast<int>(osn::FilterSubset::Audio) && subset == osn::FilterSubset::Video))
continue;

auto instance =
osn::Filter::constructor.New({
Napi::Number::New(info.Env(), response[idx].value_union.ui64)
});
array.Set(index, instance);
index++;
}
return array;
}
}

Napi::Value osn::Input::AddFilter(const Napi::CallbackInfo& info)
Expand Down Expand Up @@ -675,6 +711,66 @@ Napi::Value osn::Input::SetFilterOrder(const Napi::CallbackInfo& info)
return info.Env().Undefined();
}

Napi::Value osn::Input::SetFilterPosition(const Napi::CallbackInfo& info)
{
osn::Filter* objfilter = Napi::ObjectWrap<osn::Filter>::Unwrap(info[0].ToObject());
uint32_t position = info[1].ToNumber().Uint32Value();

auto conn = GetConnection(info);
if (!conn)
return info.Env().Undefined();

conn->call(
"Input", "PositionFilter", {ipc::value(this->sourceId), ipc::value(objfilter->sourceId), ipc::value(position), ipc::value(0)});

SourceDataInfo* sdi = CacheManager<SourceDataInfo*>::getInstance().Retrieve(this->sourceId);
if (sdi) {
sdi->filtersOrderChanged = true;
}

return info.Env().Undefined();
}

Napi::Value osn::Input::SetVideoFilterPosition(const Napi::CallbackInfo& info)
{
osn::Filter* objfilter = Napi::ObjectWrap<osn::Filter>::Unwrap(info[0].ToObject());
uint32_t position = info[1].ToNumber().Uint32Value();

auto conn = GetConnection(info);
if (!conn)
return info.Env().Undefined();

conn->call(
"Input", "PositionFilter", {ipc::value(this->sourceId), ipc::value(objfilter->sourceId), ipc::value(position), ipc::value(static_cast<int>(osn::FilterSubset::Video))});

SourceDataInfo* sdi = CacheManager<SourceDataInfo*>::getInstance().Retrieve(this->sourceId);
if (sdi) {
sdi->filtersOrderChanged = true;
}

return info.Env().Undefined();
}

Napi::Value osn::Input::SetAudioFilterPosition(const Napi::CallbackInfo& info)
{
osn::Filter* objfilter = Napi::ObjectWrap<osn::Filter>::Unwrap(info[0].ToObject());
uint32_t position = info[1].ToNumber().Uint32Value();

auto conn = GetConnection(info);
if (!conn)
return info.Env().Undefined();

conn->call(
"Input", "PositionFilter", {ipc::value(this->sourceId), ipc::value(objfilter->sourceId), ipc::value(position), ipc::value(static_cast<int>(osn::FilterSubset::Video))});

SourceDataInfo* sdi = CacheManager<SourceDataInfo*>::getInstance().Retrieve(this->sourceId);
if (sdi) {
sdi->filtersOrderChanged = true;
}

return info.Env().Undefined();
}

Napi::Value osn::Input::FindFilter(const Napi::CallbackInfo& info)
{
std::string name = info[0].ToString().Utf8Value();
Expand Down
13 changes: 13 additions & 0 deletions obs-studio-client/source/input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@

namespace osn
{
enum class FilterSubset : std::int16_t
{
All =0,
Audio = 2,
Video = 1
};
class Input : public Napi::ObjectWrap<osn::Input>
{
public:
Expand All @@ -43,6 +49,9 @@ namespace osn
Napi::Value AddFilter(const Napi::CallbackInfo& info);
Napi::Value RemoveFilter(const Napi::CallbackInfo& info);
Napi::Value SetFilterOrder(const Napi::CallbackInfo& info);
Napi::Value SetFilterPosition(const Napi::CallbackInfo& info);
Napi::Value SetVideoFilterPosition(const Napi::CallbackInfo& info);
Napi::Value SetAudioFilterPosition(const Napi::CallbackInfo& info);
Napi::Value FindFilter(const Napi::CallbackInfo& info);
Napi::Value CopyFilters(const Napi::CallbackInfo& info);

Expand All @@ -63,6 +72,10 @@ namespace osn
Napi::Value GetDeinterlaceMode(const Napi::CallbackInfo& info);
void SetDeinterlaceMode(const Napi::CallbackInfo& info, const Napi::Value &value);
Napi::Value Filters(const Napi::CallbackInfo& info);
Napi::Value VideoFilters(const Napi::CallbackInfo& info);
Napi::Value AudioFilters(const Napi::CallbackInfo& info);
Napi::Value GetFilters(const Napi::CallbackInfo& info, osn::FilterSubset subset);
Napi::Value FiltersFromCache(const Napi::CallbackInfo& info, osn::FilterSubset subset, std::vector<std::pair<uint64_t, int>> * filters);

Napi::Value CallIsConfigurable(const Napi::CallbackInfo& info);
Napi::Value CallGetProperties(const Napi::CallbackInfo& info);
Expand Down
68 changes: 66 additions & 2 deletions obs-studio-server/source/osn-input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,15 @@ void osn::Input::Register(ipc::server& srv)
"SetDeInterlaceMode", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::Int32}, GetDeInterlaceMode));

cls->register_function(
std::make_shared<ipc::function>("GetFilters", std::vector<ipc::type>{ipc::type::UInt64}, GetFilters));
std::make_shared<ipc::function>("GetFilters", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::Int32}, GetFilters));
cls->register_function(std::make_shared<ipc::function>(
"AddFilter", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt64}, AddFilter));
cls->register_function(std::make_shared<ipc::function>(
"RemoveFilter", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt64}, RemoveFilter));
cls->register_function(std::make_shared<ipc::function>(
"MoveFilter", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt64, ipc::type::UInt32}, MoveFilter));
cls->register_function(std::make_shared<ipc::function>(
"PositionFilter", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::UInt64, ipc::type::UInt32, ipc::type::UInt32}, PositionFilter));
cls->register_function(std::make_shared<ipc::function>(
"FindFilter", std::vector<ipc::type>{ipc::type::UInt64, ipc::type::String}, FindFilter));
cls->register_function(std::make_shared<ipc::function>(
Expand Down Expand Up @@ -632,6 +634,66 @@ void osn::Input::MoveFilter(
AUTO_DEBUG;
}

size_t FilterPositionInFullList(obs_source_t* input, size_t position, int subset)
{
struct filter_position_info {
size_t count;
size_t position;
size_t subset_count;
size_t full_position;
int subset;
} info = {0, position, 0, position, subset};

auto enum_cb = [](obs_source_t* parent, obs_source_t* filter, void* data) {
filter_position_info* info = reinterpret_cast<filter_position_info*>(data);
uint32_t output_flags = obs_source_get_output_flags(filter);
info->count++;
if(info->subset == OBS_SOURCE_VIDEO && (output_flags & OBS_SOURCE_VIDEO)) {
info->subset_count++;
if( info->subset_count == info->position) {
info->full_position = info->count;
}
}
if(info->subset == OBS_SOURCE_AUDIO && (output_flags & OBS_SOURCE_AUDIO)) {
info->subset_count++;
if( info->subset_count == info->position) {
info->full_position = info->count;
}
}
};

obs_source_enum_filters(input, enum_cb, &info);
return info.full_position;
}

void osn::Input::PositionFilter(
void* data,
const int64_t id,
const std::vector<ipc::value>& args,
std::vector<ipc::value>& rval)
{
obs_source_t* input = osn::Source::Manager::GetInstance().find(args[0].value_union.ui64);
if (!input) {
PRETTY_ERROR_RETURN(ErrorCode::InvalidReference, "Input reference is not valid.");
}

obs_source_t* filter = osn::Source::Manager::GetInstance().find(args[1].value_union.ui64);
if (!filter) {
PRETTY_ERROR_RETURN(ErrorCode::InvalidReference, "Filter reference is not valid.");
}

size_t position = (size_t)args[2].value_union.ui32;
int subset = args[3].value_union.ui32;

if (subset != 0)
position = FilterPositionInFullList(input, position, subset);

obs_source_filter_set_position(input, filter, position);

rval.push_back(ipc::value((uint64_t)ErrorCode::Ok));
AUTO_DEBUG;
}

void osn::Input::FindFilter(
void* data,
const int64_t id,
Expand Down Expand Up @@ -674,10 +736,12 @@ void osn::Input::GetFilters(

auto enum_cb = [](obs_source_t* parent, obs_source_t* filter, void* data) {
std::vector<ipc::value>* rval = reinterpret_cast<std::vector<ipc::value>*>(data);

uint32_t output_flags = obs_source_get_output_flags(filter);
uint64_t id = osn::Source::Manager::GetInstance().find(filter);

if (id != UINT64_MAX) {
rval->push_back(id);
rval->push_back(output_flags & (OBS_SOURCE_AUDIO|OBS_SOURCE_VIDEO));
}
};

Expand Down
5 changes: 5 additions & 0 deletions obs-studio-server/source/osn-input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ namespace osn
const int64_t id,
const std::vector<ipc::value>& args,
std::vector<ipc::value>& rval);
static void PositionFilter(
void* data,
const int64_t id,
const std::vector<ipc::value>& args,
std::vector<ipc::value>& rval);
static void FindFilter(
void* data,
const int64_t id,
Expand Down
Loading