diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index bbc02e459..89ab24e97 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -219,32 +219,44 @@ void obs_encoder_destroy(obs_encoder_t encoder) } } +static inline obs_data_t get_defaults(const struct obs_encoder_info *info) +{ + obs_data_t settings = obs_data_create(); + if (info->defaults) + info->defaults(settings); + return settings; +} + obs_data_t obs_encoder_defaults(const char *id) { const struct obs_encoder_info *info = get_encoder_info(id); - if (info) { - obs_data_t settings = obs_data_create(); - if (info->defaults) - info->defaults(settings); - return settings; - } - - return NULL; + return (info) ? get_defaults(info) : NULL; } obs_properties_t obs_get_encoder_properties(const char *id, const char *locale) { const struct obs_encoder_info *ei = get_encoder_info(id); - if (ei && ei->properties) - return ei->properties(locale); + if (ei && ei->properties) { + obs_data_t defaults = get_defaults(ei); + obs_properties_t properties; + + properties = ei->properties(locale); + obs_properties_apply_settings(properties, defaults); + obs_data_release(defaults); + return properties; + } return NULL; } obs_properties_t obs_encoder_properties(obs_encoder_t encoder, const char *locale) { - if (encoder && encoder->info.properties) - return encoder->info.properties(locale); + if (encoder && encoder->info.properties) { + obs_properties_t props; + props = encoder->info.properties(locale); + obs_properties_apply_settings(props, encoder->settings); + return props; + } return NULL; } diff --git a/libobs/obs-encoder.h b/libobs/obs-encoder.h index f96cc72ac..f34957190 100644 --- a/libobs/obs-encoder.h +++ b/libobs/obs-encoder.h @@ -36,11 +36,11 @@ struct encoder_packet { enum obs_encoder_type type; /**< Encoder type */ + bool keyframe; /**< Is a keyframe */ + /* ---------------------------------------------------------------- */ /* Internal video variables (will be parsed automatically) */ - bool keyframe; /**< Is a keyframe */ - /** * Packet priority * diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index a3c5d3364..d501021bd 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -268,6 +268,9 @@ struct obs_output { signal_handler_t signals; proc_handler_t procs; + pthread_mutex_t interleaved_mutex; + DARRAY(struct encoder_packet) interleaved_packets; + bool active; video_t video; audio_t audio; diff --git a/libobs/obs-module.c b/libobs/obs-module.c index 32db9220a..0e6d883b7 100644 --- a/libobs/obs-module.c +++ b/libobs/obs-module.c @@ -98,8 +98,10 @@ int obs_load_module(const char *path) mod.module = os_dlopen(plugin_path); bfree(plugin_path); - if (!mod.module) + if (!mod.module) { + blog(LOG_DEBUG, "Module '%s' not found", path); return MODULE_FILE_NOT_FOUND; + } errorcode = call_module_load(mod.module, path); if (errorcode != MODULE_SUCCESS) { @@ -200,7 +202,7 @@ void obs_register_output(const struct obs_output_info *info) CHECK_REQUIRED_VAL(info, stop, obs_register_output); if (info->flags & OBS_OUTPUT_ENCODED) { - CHECK_REQUIRED_VAL(info, encoded_data, obs_register_output); + CHECK_REQUIRED_VAL(info, encoded_packet, obs_register_output); } else { if (info->flags & OBS_OUTPUT_VIDEO) CHECK_REQUIRED_VAL(info, raw_video, diff --git a/libobs/obs-output.c b/libobs/obs-output.c index 76630e6b6..93e11c744 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -60,7 +60,10 @@ obs_output_t obs_output_create(const char *id, const char *name, } output = bzalloc(sizeof(struct obs_output)); + pthread_mutex_init_value(&output->interleaved_mutex); + if (pthread_mutex_init(&output->interleaved_mutex, NULL) != 0) + goto fail; if (!init_output_handlers(output)) goto fail; @@ -90,6 +93,13 @@ fail: return NULL; } +static inline void free_packets(struct obs_output *output) +{ + for (size_t i = 0; i < output->interleaved_packets.num; i++) + obs_free_encoder_packet(output->interleaved_packets.array+i); + da_free(output->interleaved_packets); +} + void obs_output_destroy(obs_output_t output) { if (output) { @@ -102,6 +112,8 @@ void obs_output_destroy(obs_output_t output) pthread_mutex_unlock(&obs->data.outputs_mutex); } + free_packets(output); + if (output->data) output->info.destroy(output->data); @@ -109,6 +121,7 @@ void obs_output_destroy(obs_output_t output) proc_handler_destroy(output->procs); obs_data_release(output->settings); + pthread_mutex_destroy(&output->interleaved_mutex); bfree(output->name); bfree(output); } @@ -130,31 +143,44 @@ bool obs_output_active(obs_output_t output) return (output != NULL) ? output->active : false; } +static inline obs_data_t get_defaults(const struct obs_output_info *info) +{ + obs_data_t settings = obs_data_create(); + if (info->defaults) + info->defaults(settings); + return settings; +} + obs_data_t obs_output_defaults(const char *id) { const struct obs_output_info *info = find_output(id); - if (info) { - obs_data_t settings = obs_data_create(); - if (info->defaults) - info->defaults(settings); - return settings; - } - - return NULL; + return (info) ? get_defaults(info) : NULL; } obs_properties_t obs_get_output_properties(const char *id, const char *locale) { const struct obs_output_info *info = find_output(id); - if (info && info->properties) - return info->properties(locale); + if (info && info->properties) { + obs_data_t defaults = get_defaults(info); + obs_properties_t properties; + + properties = info->properties(locale); + obs_properties_apply_settings(properties, defaults); + obs_data_release(defaults); + return properties; + } return NULL; } obs_properties_t obs_output_properties(obs_output_t output, const char *locale) { - if (output && output->info.properties) - return output->info.properties(locale); + if (output && output->info.properties) { + obs_properties_t props; + props = output->info.properties(locale); + obs_properties_apply_settings(props, output->settings); + return props; + } + return NULL; } @@ -316,18 +342,28 @@ static inline struct audio_convert_info *get_audio_conversion( return output->audio_conversion_set ? &output->audio_conversion : NULL; } +static void interleave_packets(void *data, struct encoder_packet *packet) +{ + +} + static void hook_data_capture(struct obs_output *output, bool encoded, bool has_video, bool has_audio) { + void (*encoded_callback)(void *data, struct encoder_packet *packet); + void *param; + if (encoded) { + encoded_callback = (has_video && has_audio) ? + interleave_packets : output->info.encoded_packet; + param = (has_video && has_audio) ? output : output->data; + if (has_video) obs_encoder_start(output->video_encoder, - output->info.encoded_data, - output->data); + encoded_callback, param); if (has_audio) obs_encoder_start(output->audio_encoder, - output->info.encoded_data, - output->data); + encoded_callback, param); } else { if (has_video) video_output_connect(output->video, @@ -405,6 +441,8 @@ bool obs_output_begin_data_capture(obs_output_t output, uint32_t flags) void obs_output_end_data_capture(obs_output_t output) { bool encoded, has_video, has_audio; + void (*encoded_callback)(void *data, struct encoder_packet *packet); + void *param; if (!output) return; if (!output->active) return; @@ -412,14 +450,16 @@ void obs_output_end_data_capture(obs_output_t output) convert_flags(output, 0, &encoded, &has_video, &has_audio); if (encoded) { + encoded_callback = (has_video && has_audio) ? + interleave_packets : output->info.encoded_packet; + param = (has_video && has_audio) ? output : output->data; + if (has_video) obs_encoder_stop(output->video_encoder, - output->info.encoded_data, - output->data); + encoded_callback, param); if (has_audio) obs_encoder_stop(output->audio_encoder, - output->info.encoded_data, - output->data); + encoded_callback, param); } else { if (has_video) video_output_disconnect(output->video, diff --git a/libobs/obs-output.h b/libobs/obs-output.h index eda95cc1c..64e8be4ca 100644 --- a/libobs/obs-output.h +++ b/libobs/obs-output.h @@ -42,7 +42,7 @@ struct obs_output_info { void (*raw_video)(void *data, struct video_data *frame); void (*raw_audio)(void *data, struct audio_data *frames); - void (*encoded_data)(void *data, struct encoder_packet *packet); + void (*encoded_packet)(void *data, struct encoder_packet *packet); /* optional */ void (*update)(void *data, obs_data_t settings); diff --git a/libobs/obs-properties.c b/libobs/obs-properties.c index ceda4358e..33d166a5e 100644 --- a/libobs/obs-properties.c +++ b/libobs/obs-properties.c @@ -33,7 +33,12 @@ struct int_data { struct list_item { char *name; - char *value; + + union { + char *str; + long long ll; + double d; + }; }; struct text_data { @@ -46,34 +51,51 @@ struct list_data { enum obs_combo_format format; }; +static inline void list_item_free(struct list_data *data, + struct list_item *item) +{ + bfree(item->name); + if (data->format == OBS_COMBO_FORMAT_STRING) + bfree(item->str); +} + static inline void list_data_free(struct list_data *data) { - for (size_t i = 0; i < data->items.num; i++) { - bfree(data->items.array[i].name); - bfree(data->items.array[i].value); - } + for (size_t i = 0; i < data->items.num; i++) + list_item_free(data, data->items.array+i); da_free(data->items); } -struct obs_property { - const char *name; - const char *desc; - enum obs_property_type type; +struct obs_properties; - struct obs_property *next; +struct obs_property { + const char *name; + const char *desc; + enum obs_property_type type; + bool visible; + bool enabled; + + struct obs_properties *parent; + + obs_property_modified_t modified; + + struct obs_property *next; }; struct obs_properties { - struct obs_property *first_property; - struct obs_property **last; + const char *locale; + + struct obs_property *first_property; + struct obs_property **last; }; -obs_properties_t obs_properties_create() +obs_properties_t obs_properties_create(const char *locale) { struct obs_properties *props; props = bzalloc(sizeof(struct obs_properties)); - props->last = &props->first_property; + props->locale = locale; + props->last = &props->first_property; return props; } @@ -101,6 +123,11 @@ void obs_properties_destroy(obs_properties_t props) } } +const char *obs_properties_locale(obs_properties_t props) +{ + return props ? props->locale : NULL; +} + obs_property_t obs_properties_first(obs_properties_t props) { return (props != NULL) ? props->first_property : NULL; @@ -124,6 +151,17 @@ obs_property_t obs_properties_get(obs_properties_t props, const char *name) return NULL; } +void obs_properties_apply_settings(obs_properties_t props, obs_data_t settings) +{ + struct obs_property *p = props->first_property; + + while (p) { + if (p->modified) + p->modified(props, p, settings); + p = p->next; + } +} + /* ------------------------------------------------------------------------- */ static inline void propertes_add(struct obs_properties *props, @@ -157,9 +195,12 @@ static inline struct obs_property *new_prop(struct obs_properties *props, struct obs_property *p; p = bzalloc(sizeof(struct obs_property) + data_size); - p->type = type; - p->name = name; - p->desc = desc; + p->parent = props; + p->enabled = true; + p->visible = true; + p->type = type; + p->name = name; + p->desc = desc; propertes_add(props, p); return p; @@ -195,29 +236,31 @@ static inline void *get_type_data(struct obs_property *prop, return get_property_data(prop); } -void obs_properties_add_bool(obs_properties_t props, const char *name, +obs_property_t obs_properties_add_bool(obs_properties_t props, const char *name, const char *desc) { - if (!props || has_prop(props, name)) return; - new_prop(props, name, desc, OBS_PROPERTY_BOOL); + if (!props || has_prop(props, name)) return NULL; + return new_prop(props, name, desc, OBS_PROPERTY_BOOL); } -void obs_properties_add_int(obs_properties_t props, const char *name, +obs_property_t obs_properties_add_int(obs_properties_t props, const char *name, const char *desc, int min, int max, int step) { - if (!props || has_prop(props, name)) return; + if (!props || has_prop(props, name)) return NULL; struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_INT); struct int_data *data = get_property_data(p); data->min = min; data->max = max; data->step = step; + return p; } -void obs_properties_add_float(obs_properties_t props, const char *name, - const char *desc, double min, double max, double step) +obs_property_t obs_properties_add_float(obs_properties_t props, + const char *name, const char *desc, + double min, double max, double step) { - if (!props || has_prop(props, name)) return; + if (!props || has_prop(props, name)) return NULL; struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_FLOAT); @@ -225,23 +268,25 @@ void obs_properties_add_float(obs_properties_t props, const char *name, data->min = min; data->max = max; data->step = step; + return p; } -void obs_properties_add_text(obs_properties_t props, const char *name, +obs_property_t obs_properties_add_text(obs_properties_t props, const char *name, const char *desc, enum obs_text_type type) { - if (!props || has_prop(props, name)) return; + if (!props || has_prop(props, name)) return NULL; struct obs_property *p = new_prop(props, name, desc, OBS_PROPERTY_TEXT); struct text_data *data = get_property_data(p); data->type = type; + return p; } -void obs_properties_add_path(obs_properties_t props, const char *name, +obs_property_t obs_properties_add_path(obs_properties_t props, const char *name, const char *desc) { - if (!props || has_prop(props, name)) return; - new_prop(props, name, desc, OBS_PROPERTY_PATH); + if (!props || has_prop(props, name)) return NULL; + return new_prop(props, name, desc, OBS_PROPERTY_PATH); } obs_property_t obs_properties_add_list(obs_properties_t props, @@ -266,11 +311,11 @@ obs_property_t obs_properties_add_list(obs_properties_t props, return p; } -void obs_properties_add_color(obs_properties_t props, const char *name, - const char *desc) +obs_property_t obs_properties_add_color(obs_properties_t props, + const char *name, const char *desc) { - if (!props || has_prop(props, name)) return; - new_prop(props, name, desc, OBS_PROPERTY_COLOR); + if (!props || has_prop(props, name)) return NULL; + return new_prop(props, name, desc, OBS_PROPERTY_COLOR); } @@ -287,18 +332,11 @@ static inline struct list_data *get_list_data(struct obs_property *p) return get_property_data(p); } -void obs_property_list_add_item(obs_property_t p, - const char *name, const char *value) +static inline struct list_data *get_list_fmt_data(struct obs_property *p, + enum obs_combo_format format) { struct list_data *data = get_list_data(p); - if (data) { - struct list_item item = { - .name = bstrdup(name), - .value = bstrdup(value) - }; - - da_push_back(data->items, &item); - } + return (data->format == format) ? data : NULL; } /* ------------------------------------------------------------------------- */ @@ -312,6 +350,29 @@ bool obs_property_next(obs_property_t *p) return *p != NULL; } +void obs_property_set_modified_callback(obs_property_t p, + obs_property_modified_t modified) +{ + if (p) p->modified = modified; +} + +bool obs_property_modified(obs_property_t p, obs_data_t settings) +{ + if (p && p->modified) + return p->modified(p->parent, p, settings); + return false; +} + +void obs_property_set_visible(obs_property_t p, bool visible) +{ + if (p) p->visible = visible; +} + +void obs_property_set_enabled(obs_property_t p, bool enabled) +{ + if (p) p->enabled = enabled; +} + const char *obs_property_name(obs_property_t p) { return p ? p->name : NULL; @@ -327,6 +388,16 @@ enum obs_property_type obs_property_get_type(obs_property_t p) return p ? p->type : OBS_PROPERTY_INVALID; } +bool obs_property_enabled(obs_property_t p) +{ + return p ? p->enabled : false; +} + +bool obs_property_visible(obs_property_t p) +{ + return p ? p->visible : false; +} + int obs_property_int_min(obs_property_t p) { struct int_data *data = get_type_data(p, OBS_PROPERTY_INT); @@ -381,6 +452,61 @@ enum obs_combo_format obs_property_list_format(obs_property_t p) return data ? data->format : OBS_COMBO_FORMAT_INVALID; } +void obs_property_list_clear(obs_property_t p) +{ + struct list_data *data = get_list_data(p); + if (data) + list_data_free(data); +} + +static void add_item(struct list_data *data, const char *name, const void *val) +{ + struct list_item item; + item.name = bstrdup(name); + + if (data->format == OBS_COMBO_FORMAT_INT) + item.ll = *(const long long*)val; + else if (data->format == OBS_COMBO_FORMAT_FLOAT) + item.d = *(const double*)val; + else + item.str = bstrdup(val); + + da_push_back(data->items, &item); +} + +void obs_property_list_add_string(obs_property_t p, + const char *name, const char *val) +{ + struct list_data *data = get_list_data(p); + if (data && data->format == OBS_COMBO_FORMAT_STRING) + add_item(data, name, val); +} + +void obs_property_list_add_int(obs_property_t p, + const char *name, long long val) +{ + struct list_data *data = get_list_data(p); + if (data && data->format == OBS_COMBO_FORMAT_INT) + add_item(data, name, &val); +} + +void obs_property_list_add_float(obs_property_t p, + const char *name, double val) +{ + struct list_data *data = get_list_data(p); + if (data && data->format == OBS_COMBO_FORMAT_FLOAT) + add_item(data, name, &val); +} + +void obs_property_list_item_remove(obs_property_t p, size_t idx) +{ + struct list_data *data = get_list_data(p); + if (data && idx < data->items.num) { + list_item_free(data, data->items.array+idx); + da_erase(data->items, idx); + } +} + size_t obs_property_list_item_count(obs_property_t p) { struct list_data *data = get_list_data(p); @@ -394,9 +520,23 @@ const char *obs_property_list_item_name(obs_property_t p, size_t idx) data->items.array[idx].name : NULL; } -const char *obs_property_list_item_value(obs_property_t p, size_t idx) +const char *obs_property_list_item_string(obs_property_t p, size_t idx) { - struct list_data *data = get_list_data(p); + struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_STRING); return (data && idx < data->items.num) ? - data->items.array[idx].value : NULL; + data->items.array[idx].str : ""; +} + +long long obs_property_list_item_int(obs_property_t p, size_t idx) +{ + struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_INT); + return (data && idx < data->items.num) ? + data->items.array[idx].ll : 0; +} + +double obs_property_list_item_float(obs_property_t p, size_t idx) +{ + struct list_data *data = get_list_fmt_data(p, OBS_COMBO_FORMAT_FLOAT); + return (data && idx < data->items.num) ? + data->items.array[idx].d : 0.0; } diff --git a/libobs/obs-properties.h b/libobs/obs-properties.h index 0fa63517b..879688816 100644 --- a/libobs/obs-properties.h +++ b/libobs/obs-properties.h @@ -18,6 +18,7 @@ #pragma once #include "util/c99defs.h" +#include "obs-data.h" #ifdef __cplusplus extern "C" { @@ -59,40 +60,64 @@ typedef struct obs_property *obs_property_t; /* ------------------------------------------------------------------------- */ -EXPORT obs_properties_t obs_properties_create(); +EXPORT obs_properties_t obs_properties_create(const char *locale); EXPORT void obs_properties_destroy(obs_properties_t props); +EXPORT const char *obs_properties_locale(obs_properties_t props); + EXPORT obs_property_t obs_properties_first(obs_properties_t props); EXPORT obs_property_t obs_properties_get(obs_properties_t props, const char *property); +/* used internally by libobs */ +extern void obs_properties_apply_settings(obs_properties_t props, + obs_data_t settings); + /* ------------------------------------------------------------------------- */ -EXPORT void obs_properties_add_bool(obs_properties_t props, const char *name, - const char *description); -EXPORT void obs_properties_add_int(obs_properties_t props, const char *name, - const char *description, int min, int max, int step); -EXPORT void obs_properties_add_float(obs_properties_t props, const char *name, - const char *description, double min, double max, double step); -EXPORT void obs_properties_add_text(obs_properties_t props, const char *name, - const char *description, enum obs_text_type type); -EXPORT void obs_properties_add_path(obs_properties_t props, const char *name, - const char *description); +EXPORT obs_property_t obs_properties_add_bool(obs_properties_t props, + const char *name, const char *description); +EXPORT obs_property_t obs_properties_add_int(obs_properties_t props, + const char *name, const char *description, + int min, int max, int step); +EXPORT obs_property_t obs_properties_add_float(obs_properties_t props, + const char *name, const char *description, + double min, double max, double step); +EXPORT obs_property_t obs_properties_add_text(obs_properties_t props, + const char *name, const char *description, + enum obs_text_type type); +EXPORT obs_property_t obs_properties_add_path(obs_properties_t props, + const char *name, const char *description); EXPORT obs_property_t obs_properties_add_list(obs_properties_t props, const char *name, const char *description, enum obs_combo_type type, enum obs_combo_format format); -EXPORT void obs_properties_add_color(obs_properties_t props, const char *name, - const char *description); - -EXPORT void obs_property_list_add_item(obs_property_t p, - const char *name, const char *value); +EXPORT obs_property_t obs_properties_add_color(obs_properties_t props, + const char *name, const char *description); /* ------------------------------------------------------------------------- */ +/** + * Optional callback for when a property is modified. If the properties + * need to be refreshed due to changes to the property layout, return true, + * otherwise return false. + */ +typedef bool (*obs_property_modified_t)(obs_properties_t props, + obs_property_t property, obs_data_t settings); + +EXPORT void obs_property_set_modified_callback(obs_property_t p, + obs_property_modified_t modified); + +EXPORT bool obs_property_modified(obs_property_t p, obs_data_t settings); + +EXPORT void obs_property_set_visible(obs_property_t p, bool visible); +EXPORT void obs_property_set_enabled(obs_property_t p, bool enabled); + EXPORT const char * obs_property_name(obs_property_t p); EXPORT const char * obs_property_description(obs_property_t p); EXPORT enum obs_property_type obs_property_get_type(obs_property_t p); +EXPORT bool obs_property_enabled(obs_property_t p); +EXPORT bool obs_property_visible(obs_property_t p); EXPORT bool obs_property_next(obs_property_t *p); @@ -106,9 +131,22 @@ EXPORT enum obs_text_type obs_proprety_text_type(obs_property_t p); EXPORT enum obs_combo_type obs_property_list_type(obs_property_t p); EXPORT enum obs_combo_format obs_property_list_format(obs_property_t p); +EXPORT void obs_property_list_clear(obs_property_t p); + +EXPORT void obs_property_list_add_string(obs_property_t p, + const char *name, const char *val); +EXPORT void obs_property_list_add_int(obs_property_t p, + const char *name, long long val); +EXPORT void obs_property_list_add_float(obs_property_t p, + const char *name, double val); + +EXPORT void obs_property_list_remove(obs_property_t p, size_t idx); + EXPORT size_t obs_property_list_item_count(obs_property_t p); EXPORT const char *obs_property_list_item_name(obs_property_t p, size_t idx); -EXPORT const char *obs_property_list_item_value(obs_property_t p, size_t idx); +EXPORT const char *obs_property_list_item_string(obs_property_t p, size_t idx); +EXPORT long long obs_property_list_item_int(obs_property_t p, size_t idx); +EXPORT double obs_property_list_item_float(obs_property_t p, size_t idx); #ifdef __cplusplus } diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 7561acd3c..1356e743f 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -314,32 +314,45 @@ bool obs_source_removed(obs_source_t source) return source ? source->removed : true; } +static inline obs_data_t get_defaults(const struct obs_source_info *info) +{ + obs_data_t settings = obs_data_create(); + if (info->defaults) + info->defaults(settings); + return settings; +} + obs_data_t obs_source_settings(enum obs_source_type type, const char *id) { const struct obs_source_info *info = get_source_info(type, id); - if (info) { - obs_data_t settings = obs_data_create(); - if (info->defaults) - info->defaults(settings); - return settings; - } - - return NULL; + return (info) ? get_defaults(info) : NULL; } obs_properties_t obs_get_source_properties(enum obs_source_type type, const char *id, const char *locale) { const struct obs_source_info *info = get_source_info(type, id); - if (info && info->properties) - return info->properties(locale); + if (info && info->properties) { + obs_data_t defaults = get_defaults(info); + obs_properties_t properties; + + properties = info->properties(locale); + obs_properties_apply_settings(properties, defaults); + obs_data_release(defaults); + return properties; + } return NULL; } obs_properties_t obs_source_properties(obs_source_t source, const char *locale) { - if (source && source->info.properties) - return source->info.properties(locale); + if (source && source->info.properties) { + obs_properties_t props; + props = source->info.properties(locale); + obs_properties_apply_settings(props, source->settings); + return props; + } + return NULL; } diff --git a/obs/properties-view.cpp b/obs/properties-view.cpp index 38efb3afa..c9de3987a 100644 --- a/obs/properties-view.cpp +++ b/obs/properties-view.cpp @@ -11,15 +11,12 @@ using namespace std; -OBSPropertiesView::OBSPropertiesView(OBSData settings_, - obs_properties_t properties_, void *obj_, - PropertiesUpdateCallback callback_) - : QScrollArea (nullptr), - properties (properties_), - settings (settings_), - obj (obj_), - callback (callback_) +void OBSPropertiesView::RefreshProperties() { + children.clear(); + if (widget) + widget->deleteLater(); + widget = new QWidget(); QFormLayout *layout = new QFormLayout; @@ -41,6 +38,19 @@ OBSPropertiesView::OBSPropertiesView(OBSData settings_, setSizePolicy(policy); } +OBSPropertiesView::OBSPropertiesView(OBSData settings_, + obs_properties_t properties_, void *obj_, + PropertiesUpdateCallback callback_) + : QScrollArea (nullptr), + widget (nullptr), + properties (properties_), + settings (settings_), + obj (obj_), + callback (callback_) +{ + RefreshProperties(); +} + QWidget *OBSPropertiesView::NewWidget(obs_property_t prop, QWidget *widget, const char *signal) { @@ -76,11 +86,12 @@ QWidget *OBSPropertiesView::AddText(obs_property_t prop) return NewWidget(prop, edit, SIGNAL(textEdited(const QString &))); } -void OBSPropertiesView::AddPath(obs_property_t prop, QFormLayout *layout) +QWidget *OBSPropertiesView::AddPath(obs_property_t prop, QFormLayout *layout) { /* TODO */ UNUSED_PARAMETER(prop); UNUSED_PARAMETER(layout); + return nullptr; } QWidget *OBSPropertiesView::AddInt(obs_property_t prop) @@ -111,6 +122,27 @@ QWidget *OBSPropertiesView::AddFloat(obs_property_t prop) return NewWidget(prop, spin, SIGNAL(valueChanged(double))); } +static void AddComboItem(QComboBox *combo, obs_property_t prop, + obs_combo_format format, size_t idx) +{ + const char *name = obs_property_list_item_name(prop, idx); + QVariant var; + + if (format == OBS_COMBO_FORMAT_INT) { + long long val = obs_property_list_item_int(prop, idx); + var = QVariant::fromValue(val); + + } else if (format == OBS_COMBO_FORMAT_FLOAT) { + double val = obs_property_list_item_float(prop, idx); + var = QVariant::fromValue(val); + + } else if (format == OBS_COMBO_FORMAT_STRING) { + var = obs_property_list_item_string(prop, idx); + } + + combo->addItem(QT_UTF8(name), var); +} + QWidget *OBSPropertiesView::AddList(obs_property_t prop) { const char *name = obs_property_name(prop); @@ -120,11 +152,8 @@ QWidget *OBSPropertiesView::AddList(obs_property_t prop) size_t count = obs_property_list_item_count(prop); int idx = -1; - for (size_t i = 0; i < count; i++) { - const char *name = obs_property_list_item_name(prop, i); - const char *val = obs_property_list_item_value(prop, i); - combo->addItem(QT_UTF8(name), QT_UTF8(val)); - } + for (size_t i = 0; i < count; i++) + AddComboItem(combo, prop, format, i); if (format == OBS_COMBO_FORMAT_INT) { int val = (int)obs_data_getint(settings, name); @@ -154,7 +183,16 @@ QWidget *OBSPropertiesView::AddList(obs_property_t prop) if (idx != -1) combo->setCurrentIndex(idx); - return NewWidget(prop, combo, SIGNAL(currentIndexChanged(int))); + WidgetInfo *info = new WidgetInfo(this, prop, combo); + connect(combo, SIGNAL(currentIndexChanged(int)), info, + SLOT(ControlChanged())); + children.push_back(std::move(unique_ptr(info))); + + /* trigger a settings update if the index was not found */ + if (idx == -1) + info->ControlChanged(); + + return combo; } void OBSPropertiesView::AddProperty(obs_property_t property, @@ -162,6 +200,9 @@ void OBSPropertiesView::AddProperty(obs_property_t property, { obs_property_type type = obs_property_get_type(property); + if (!obs_property_visible(property)) + return; + QWidget *widget = nullptr; switch (type) { @@ -193,6 +234,9 @@ void OBSPropertiesView::AddProperty(obs_property_t property, if (!widget) return; + if (!obs_property_enabled(property)) + widget->setEnabled(false); + QLabel *label = nullptr; if (type != OBS_PROPERTY_BOOL) label = new QLabel(QT_UTF8(obs_property_description(property))); @@ -236,29 +280,32 @@ void WidgetInfo::ListChanged(const char *setting) QComboBox *combo = static_cast(widget); obs_combo_format format = obs_property_list_format(property); obs_combo_type type = obs_property_list_type(property); + QVariant data; - string val; if (type == OBS_COMBO_TYPE_EDITABLE) { - val = QT_TO_UTF8(combo->currentText()); + data = combo->currentText(); } else { int index = combo->currentIndex(); - if (index != -1) { - QVariant variant = combo->itemData(index); - val = QT_TO_UTF8(variant.toString()); - } + if (index != -1) + data = combo->itemData(index); + else + return; } switch (format) { case OBS_COMBO_FORMAT_INVALID: return; case OBS_COMBO_FORMAT_INT: - obs_data_setint(view->settings, setting, stol(val)); + obs_data_setint(view->settings, setting, + data.value()); break; case OBS_COMBO_FORMAT_FLOAT: - obs_data_setdouble(view->settings, setting, stod(val)); + obs_data_setdouble(view->settings, setting, + data.value()); break; case OBS_COMBO_FORMAT_STRING: - obs_data_setstring(view->settings, setting, val.c_str()); + obs_data_setstring(view->settings, setting, + QT_TO_UTF8(data.toString())); break; } } @@ -286,4 +333,6 @@ void WidgetInfo::ControlChanged() } view->callback(view->obj, view->settings); + if (obs_property_modified(property, view->settings)) + view->RefreshProperties(); } diff --git a/obs/properties-view.hpp b/obs/properties-view.hpp index c0d8d6730..53fb56639 100644 --- a/obs/properties-view.hpp +++ b/obs/properties-view.hpp @@ -53,12 +53,14 @@ private: PropertiesUpdateCallback callback; std::vector> children; + void RefreshProperties(); + QWidget *NewWidget(obs_property_t prop, QWidget *widget, const char *signal); QWidget *AddCheckbox(obs_property_t prop); QWidget *AddText(obs_property_t prop); - void AddPath(obs_property_t prop, QFormLayout *layout); + QWidget *AddPath(obs_property_t prop, QFormLayout *layout); QWidget *AddInt(obs_property_t prop); QWidget *AddFloat(obs_property_t prop); QWidget *AddList(obs_property_t prop); diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index ae53d690e..7b84ce2ae 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -354,7 +354,7 @@ void OBSBasicSettings::LoadListValues(QComboBox *widget, obs_property_t prop, for (size_t i = 0; i < count; i++) { const char *name = obs_property_list_item_name(prop, i); - const char *val = obs_property_list_item_value(prop, i); + const char *val = obs_property_list_item_string(prop, i); LoadListValue(widget, name, val); } diff --git a/plugins/linux-pulseaudio/pulse-input.c b/plugins/linux-pulseaudio/pulse-input.c index abbd2299c..39522d3cb 100644 --- a/plugins/linux-pulseaudio/pulse-input.c +++ b/plugins/linux-pulseaudio/pulse-input.c @@ -506,7 +506,7 @@ static void pulse_source_info(pa_context *c, const pa_source_info *i, int eol, blog(LOG_DEBUG, "pulse-input: Got source #%u '%s'", i->index, i->description); - obs_property_list_add_item(e->devices, i->description, i->name); + obs_property_list_add_string(e->devices, i->description, i->name); pa_threaded_mainloop_signal(e->mainloop, 0); } @@ -553,11 +553,9 @@ fail: */ static obs_properties_t pulse_properties(const char *locale, bool input) { - UNUSED_PARAMETER(locale); - blog(LOG_DEBUG, "pulse-input: properties requested !"); - obs_properties_t props = obs_properties_create(); + obs_properties_t props = obs_properties_create(locale); pulse_enumerate_devices(props, input); diff --git a/plugins/mac-capture/mac-audio.c b/plugins/mac-capture/mac-audio.c index 3c7c430b4..e48f943fc 100644 --- a/plugins/mac-capture/mac-audio.c +++ b/plugins/mac-capture/mac-audio.c @@ -709,7 +709,7 @@ static void *coreaudio_create_output_capture(obs_data_t settings, static obs_properties_t coreaudio_properties(const char *locale, bool input) { - obs_properties_t props = obs_properties_create(); + obs_properties_t props = obs_properties_create(locale); obs_property_t property; struct device_list devices; @@ -723,17 +723,15 @@ static obs_properties_t coreaudio_properties(const char *locale, bool input) /* TODO: translate */ if (devices.items.num) - obs_property_list_add_item(property, "Default", "default"); + obs_property_list_add_string(property, "Default", "default"); for (size_t i = 0; i < devices.items.num; i++) { struct device_item *item = devices.items.array+i; - obs_property_list_add_item(property, + obs_property_list_add_string(property, item->name.array, item->value.array); } device_list_free(&devices); - - UNUSED_PARAMETER(locale); return props; } diff --git a/plugins/obs-outputs/rtmp-stream.c b/plugins/obs-outputs/rtmp-stream.c index 9711737b8..d110b6737 100644 --- a/plugins/obs-outputs/rtmp-stream.c +++ b/plugins/obs-outputs/rtmp-stream.c @@ -383,7 +383,7 @@ static void rtmp_stream_data(void *data, struct encoder_packet *packet) static obs_properties_t rtmp_stream_properties(const char *locale) { - obs_properties_t props = obs_properties_create(); + obs_properties_t props = obs_properties_create(locale); /* TODO: locale */ obs_properties_add_text(props, "path", "Stream URL", OBS_TEXT_DEFAULT); @@ -392,19 +392,18 @@ static obs_properties_t rtmp_stream_properties(const char *locale) OBS_TEXT_DEFAULT); obs_properties_add_text(props, "password", "Password", OBS_TEXT_PASSWORD); - - UNUSED_PARAMETER(locale); return props; } struct obs_output_info rtmp_output_info = { - .id = "rtmp_output", - .flags = OBS_OUTPUT_AV | OBS_OUTPUT_ENCODED | OBS_OUTPUT_SERVICE, - .getname = rtmp_stream_getname, - .create = rtmp_stream_create, - .destroy = rtmp_stream_destroy, - .start = rtmp_stream_start, - .stop = rtmp_stream_stop, - .encoded_data = rtmp_stream_data, + .id = "rtmp_output", + .flags = OBS_OUTPUT_AV | + OBS_OUTPUT_ENCODED, + .getname = rtmp_stream_getname, + .create = rtmp_stream_create, + .destroy = rtmp_stream_destroy, + .start = rtmp_stream_start, + .stop = rtmp_stream_stop, + .encoded_packet = rtmp_stream_data, .properties = rtmp_stream_properties }; diff --git a/plugins/obs-x264/obs-x264.c b/plugins/obs-x264/obs-x264.c index 96ee26206..e4fb48e6b 100644 --- a/plugins/obs-x264/obs-x264.c +++ b/plugins/obs-x264/obs-x264.c @@ -86,17 +86,16 @@ static void obs_x264_defaults(obs_data_t settings) static inline void add_strings(obs_property_t list, const char *const *strings) { while (*strings) { - obs_property_list_add_item(list, *strings, *strings); + obs_property_list_add_string(list, *strings, *strings); strings++; } } static obs_properties_t obs_x264_props(const char *locale) { - UNUSED_PARAMETER(locale); /* TODO: locale */ - obs_properties_t props = obs_properties_create(); + obs_properties_t props = obs_properties_create(locale); obs_property_t list; obs_properties_add_int(props, "bitrate", "Bitrate", 50, 100000, 1); @@ -113,9 +112,9 @@ static obs_properties_t obs_x264_props(const char *locale) list = obs_properties_add_list(props, "profile", "Profile", OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); - obs_property_list_add_item(list, "baseline", "baseline"); - obs_property_list_add_item(list, "main", "main"); - obs_property_list_add_item(list, "high", "high"); + obs_property_list_add_string(list, "baseline", "baseline"); + obs_property_list_add_string(list, "main", "main"); + obs_property_list_add_string(list, "high", "high"); list = obs_properties_add_list(props, "tune", "Tune", OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); diff --git a/plugins/win-wasapi/win-wasapi.cpp b/plugins/win-wasapi/win-wasapi.cpp index b9ca54a6d..335b6b82b 100644 --- a/plugins/win-wasapi/win-wasapi.cpp +++ b/plugins/win-wasapi/win-wasapi.cpp @@ -468,7 +468,7 @@ static void UpdateWASAPISource(void *obj, obs_data_t settings) static obs_properties_t GetWASAPIProperties(const char *locale, bool input) { - obs_properties_t props = obs_properties_create(); + obs_properties_t props = obs_properties_create(locale); vector devices; /* TODO: translate */ @@ -479,15 +479,16 @@ static obs_properties_t GetWASAPIProperties(const char *locale, bool input) GetWASAPIAudioDevices(devices, input); if (devices.size()) - obs_property_list_add_item(device_prop, "Default", "default"); + obs_property_list_add_string(device_prop, "Default", "default"); for (size_t i = 0; i < devices.size(); i++) { AudioDeviceInfo &device = devices[i]; - obs_property_list_add_item(device_prop, + obs_property_list_add_string(device_prop, device.name.c_str(), device.id.c_str()); } - obs_properties_add_bool(props, "use_device_timing", + obs_property_t prop; + prop = obs_properties_add_bool(props, "use_device_timing", "Use Device Timing"); return props; diff --git a/test/test-input/test-desktop.m b/test/test-input/test-desktop.m index bcd508bb9..7c95a1845 100644 --- a/test/test-input/test-desktop.m +++ b/test/test-input/test-desktop.m @@ -263,18 +263,16 @@ static void display_capture_update(void *data, obs_data_t settings) static obs_properties_t display_capture_properties(char const *locale) { - UNUSED_PARAMETER(locale); - obs_properties_t props = obs_properties_create(); + obs_properties_t props = obs_properties_create(locale); obs_property_t list = obs_properties_add_list(props, "display", "Display", OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - for (unsigned i = 0; i < [NSScreen screens].count; i++) - { + for (unsigned i = 0; i < [NSScreen screens].count; i++) { char buf[10]; sprintf(buf, "%u", i); - obs_property_list_add_item(list, buf, buf); + obs_property_list_add_int(list, buf, i); } return props;