const char *get_font_path(const char *family, uint16_t size, const char *style, uint32_t flags, FT_Long *idx) { const char *best_path = NULL; double best_rating = 0.0; struct dstr face_and_style = {0}; struct dstr style_str = {0}; bool bold = !!(flags & OBS_FONT_BOLD); bool italic = !!(flags & OBS_FONT_ITALIC); if (!family || !*family) return NULL; if (style) { dstr_copy(&style_str, style); dstr_replace(&style_str, "Bold", ""); dstr_replace(&style_str, "Italic", ""); dstr_replace(&style_str, " ", " "); dstr_depad(&style_str); } dstr_copy(&face_and_style, family); if (!dstr_is_empty(&style_str)) { dstr_cat(&face_and_style, " "); dstr_cat_dstr(&face_and_style, &style_str); } for (size_t i = 0; i < font_list.num; i++) { struct font_path_info *info = font_list.array + i; double rating = (double)get_rating(info, &face_and_style); if (rating < info->face_len) continue; if (info->is_bitmap) { int best_diff = 1000; for (size_t j = 0; j < info->num_sizes; j++) { int diff = abs(info->sizes[j] - size); if (diff < best_diff) best_diff = diff; } rating /= (double)(best_diff + 1.0); } if (info->bold == bold) rating += 1.0; if (info->italic == italic) rating += 1.0; if (rating > best_rating) { best_path = info->path; *idx = info->index; best_rating = rating; } } dstr_free(&style_str); dstr_free(&face_and_style); return best_path; }
static inline char *decode_str(const char *src) { struct dstr str = {0}; dstr_copy(&str, src); dstr_replace(&str, "#3A", ":"); dstr_replace(&str, "#22", "#"); return str.array; }
int config_save(config_t *config) { FILE *f; struct dstr str, tmp; size_t i, j; if (!config) return CONFIG_ERROR; if (!config->file) return CONFIG_ERROR; dstr_init(&str); dstr_init(&tmp); f = os_fopen(config->file, "wb"); if (!f) return CONFIG_FILENOTFOUND; for (i = 0; i < config->sections.num; i++) { struct config_section *section = darray_item( sizeof(struct config_section), &config->sections, i); if (i) dstr_cat(&str, "\n"); dstr_cat(&str, "["); dstr_cat(&str, section->name); dstr_cat(&str, "]\n"); for (j = 0; j < section->items.num; j++) { struct config_item *item = darray_item( sizeof(struct config_item), §ion->items, j); dstr_copy(&tmp, item->value ? item->value : ""); dstr_replace(&tmp, "\\", "\\\\"); dstr_replace(&tmp, "\r", "\\r"); dstr_replace(&tmp, "\n", "\\n"); dstr_cat(&str, item->name); dstr_cat(&str, "="); dstr_cat(&str, tmp.array); dstr_cat(&str, "\n"); } } #ifdef _WIN32 fwrite("\xEF\xBB\xBF", 1, 3, f); #endif fwrite(str.array, 1, str.len, f); fclose(f); dstr_free(&tmp); dstr_free(&str); return CONFIG_SUCCESS; }
void dstr_safe_printf(struct dstr *dst, const char *format, const char *val1, const char *val2, const char *val3, const char *val4) { dstr_copy(dst, format); if (val1) dstr_replace(dst, "$1", val1); if (val2) dstr_replace(dst, "$2", val2); if (val3) dstr_replace(dst, "$3", val3); if (val4) dstr_replace(dst, "$4", val4); }
static void config_add_item(struct darray *items, struct strref *name, struct strref *value) { struct config_item item; struct dstr item_value; dstr_init_copy_strref(&item_value, value); dstr_replace(&item_value, "\\n", "\n"); dstr_replace(&item_value, "\\r", "\r"); dstr_replace(&item_value, "\\\\", "\\"); item.name = bstrdup_n(name->array, name->len); item.value = item_value.array; darray_push_back(sizeof(struct config_item), items, &item); }
static void add_font_path(FT_Face face, FT_Long idx, const char *family_in, const char *style_in, const char *path) { struct dstr face_and_style = {0}; struct font_path_info info; if (!family_in || !path) return; dstr_copy(&face_and_style, family_in); if (face->style_name) { struct dstr style = {0}; dstr_copy(&style, style_in); dstr_replace(&style, "Bold", ""); dstr_replace(&style, "Italic", ""); dstr_replace(&style, " ", " "); dstr_depad(&style); if (!dstr_is_empty(&style)) { dstr_cat(&face_and_style, " "); dstr_cat_dstr(&face_and_style, &style); } dstr_free(&style); } info.face_and_style = face_and_style.array; info.full_len = face_and_style.len; info.face_len = strlen(family_in); info.is_bitmap = !!(face->face_flags & FT_FACE_FLAG_FIXED_SIZES); info.bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD); info.italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC); info.index = idx; info.path = bstrdup(path); create_bitmap_sizes(&info, face); da_push_back(font_list, &info); /*blog(LOG_DEBUG, "name: %s\n\tstyle: %s\n\tpath: %s\n", family_in, style_in, path);*/ }
static bool parse_binary_from_directory(struct dstr *parsed_bin_path, const char *bin_path, const char *file) { struct dstr directory = {0}; bool found = true; dstr_copy(&directory, bin_path); dstr_replace(&directory, "%module%", file); if (dstr_end(&directory) != '/') dstr_cat_ch(&directory, '/'); dstr_copy_dstr(parsed_bin_path, &directory); dstr_cat(parsed_bin_path, file); dstr_cat(parsed_bin_path, get_module_extension()); if (!os_file_exists(parsed_bin_path->array)) { /* if the file doesn't exist, check with 'lib' prefix */ dstr_copy_dstr(parsed_bin_path, &directory); dstr_cat(parsed_bin_path, "lib"); dstr_cat(parsed_bin_path, file); dstr_cat(parsed_bin_path, get_module_extension()); /* if neither exist, don't include this as a library */ if (!os_file_exists(parsed_bin_path->array)) { dstr_free(parsed_bin_path); found = false; } } dstr_free(&directory); return found; }
static bool ffmpeg_mux_start(void *data) { struct ffmpeg_muxer *stream = data; obs_data_t *settings; struct dstr cmd; const char *path; if (!obs_output_can_begin_data_capture(stream->output, 0)) return false; if (!obs_output_initialize_encoders(stream->output, 0)) return false; settings = obs_output_get_settings(stream->output); path = obs_data_get_string(settings, "path"); dstr_copy(&stream->path, path); dstr_replace(&stream->path, "\"", "\"\""); obs_data_release(settings); build_command_line(stream, &cmd); stream->pipe = os_process_pipe_create(cmd.array, "w"); dstr_free(&cmd); if (!stream->pipe) { warn("Failed to create process pipe"); return false; } /* write headers and start capture */ stream->active = true; stream->capturing = true; obs_output_begin_data_capture(stream->output, 0); info("Writing file '%s'...", stream->path.array); return true; }
static obs_properties_t *image_source_properties(void *data) { struct image_source *s = data; struct dstr path = {0}; obs_properties_t *props = obs_properties_create(); if (s && s->file && *s->file) { const char *slash; dstr_copy(&path, s->file); dstr_replace(&path, "\\", "/"); slash = strrchr(path.array, '/'); if (slash) dstr_resize(&path, slash - path.array + 1); } obs_properties_add_path(props, "file", obs_module_text("File"), OBS_PATH_FILE, image_filter, path.array); obs_properties_add_bool(props, "unload", obs_module_text("UnloadWhenNotShowing")); dstr_free(&path); return props; }
static obs_properties_t *color_grade_filter_properties(void *data) { struct lut_filter_data *s = data; struct dstr path = {0}; const char *slash; obs_properties_t *props = obs_properties_create(); struct dstr filter_str = {0}; dstr_cat(&filter_str, "(*.png)"); if (s && s->file && *s->file) { dstr_copy(&path, s->file); } else { dstr_copy(&path, obs_module_file("LUTs")); dstr_cat_ch(&path, '/'); } dstr_replace(&path, "\\", "/"); slash = strrchr(path.array, '/'); if (slash) dstr_resize(&path, slash - path.array + 1); obs_properties_add_path(props, SETTING_IMAGE_PATH, TEXT_IMAGE_PATH, OBS_PATH_FILE, filter_str.array, path.array); obs_properties_add_float_slider(props, SETTING_CLUT_AMOUNT, TEXT_AMOUNT, 0, 1, 0.01); dstr_free(&filter_str); UNUSED_PARAMETER(data); return props; }
static inline void make_data_dir(struct dstr *parsed_data_dir, const char *data_dir, const char *name) { dstr_copy(parsed_data_dir, data_dir); dstr_replace(parsed_data_dir, "%module%", name); if (dstr_end(parsed_data_dir) == '/') dstr_resize(parsed_data_dir, parsed_data_dir->len - 1); }
void *os_dlopen(const char *path) { struct dstr dll_name; wchar_t *wpath; wchar_t *wpath_slash; HMODULE h_library = NULL; if (!path) return NULL; dstr_init_copy(&dll_name, path); dstr_replace(&dll_name, "\\", "/"); if (!dstr_find(&dll_name, ".dll")) dstr_cat(&dll_name, ".dll"); os_utf8_to_wcs_ptr(dll_name.array, 0, &wpath); /* to make module dependency issues easier to deal with, allow * dynamically loaded libraries on windows to search for dependent * libraries that are within the library's own directory */ wpath_slash = wcsrchr(wpath, L'/'); if (wpath_slash) { *wpath_slash = 0; SetDllDirectoryW(wpath); *wpath_slash = L'/'; } h_library = LoadLibraryW(wpath); bfree(wpath); dstr_free(&dll_name); if (wpath_slash) SetDllDirectoryW(NULL); if (!h_library) { DWORD error = GetLastError(); char *message = NULL; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&message, 0, NULL); blog(LOG_INFO, "LoadLibrary failed for '%s': %s (%lu)", path, message, error); if (message) LocalFree(message); } return h_library; }
int os_mkdirs(const char *dir) { struct dstr dir_str; int ret; dstr_init_copy(&dir_str, dir); dstr_replace(&dir_str, "\\", "/"); ret = recursive_mkdir(dir_str.array); dstr_free(&dir_str); return ret; }
static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder) { obs_data_t *settings = obs_encoder_get_settings(aencoder); int bitrate = (int)obs_data_get_int(settings, "bitrate"); audio_t *audio = obs_get_audio(); struct dstr name = {0}; obs_data_release(settings); dstr_copy(&name, obs_encoder_get_name(aencoder)); dstr_replace(&name, "\"", "\"\""); dstr_catf(cmd, "\"%s\" %d %d %d ", name.array, bitrate, (int)obs_encoder_get_sample_rate(aencoder), (int)audio_output_get_channels(audio)); dstr_free(&name); }
const char *os_get_path_extension(const char *path) { struct dstr temp; size_t pos = 0; char *period; char *slash; dstr_init_copy(&temp, path); dstr_replace(&temp, "\\", "/"); slash = strrchr(temp.array, '/'); period = strrchr(temp.array, '.'); if (period) pos = (size_t)(period - temp.array); dstr_free(&temp); if (!period || slash > period) return NULL; return path + pos; }
/* ugh, don't ask. I'll probably get rid of the need for this function later */ static void gl_rename_attributes(struct gl_shader_parser *glsp) { size_t i = 0, input_idx = 0, output_idx = 0; for (i = 0; i < glsp->attribs.num; i++) { struct gl_parser_attrib *attrib = glsp->attribs.array+i; struct dstr new_name = {0}; const char *prefix; size_t val; if (attrib->input) { prefix = glsp->input_prefix; val = input_idx++; } else { prefix = glsp->output_prefix; val = output_idx++; } dstr_printf(&new_name, "%s%u", prefix, val); dstr_replace(&glsp->gl_string, attrib->name.array, new_name.array); dstr_move(&attrib->name, &new_name); } }
static inline void encode_dstr(struct dstr *str) { dstr_replace(str, "#", "#22"); dstr_replace(str, ":", "#3A"); }
static obs_properties_t *ffmpeg_source_getproperties(void *data) { struct ffmpeg_source *s = data; struct dstr filter = {0}; struct dstr path = {0}; UNUSED_PARAMETER(data); obs_properties_t *props = obs_properties_create(); obs_properties_set_flags(props, OBS_PROPERTIES_DEFER_UPDATE); obs_property_t *prop; // use this when obs allows non-readonly paths prop = obs_properties_add_bool(props, "is_local_file", obs_module_text("LocalFile")); obs_property_set_modified_callback(prop, is_local_file_modified); dstr_copy(&filter, obs_module_text("MediaFileFilter.AllMediaFiles")); dstr_cat(&filter, media_filter); dstr_cat(&filter, obs_module_text("MediaFileFilter.VideoFiles")); dstr_cat(&filter, video_filter); dstr_cat(&filter, obs_module_text("MediaFileFilter.AudioFiles")); dstr_cat(&filter, audio_filter); dstr_cat(&filter, obs_module_text("MediaFileFilter.AllFiles")); dstr_cat(&filter, " (*.*)"); if (s && s->input && *s->input) { const char *slash; dstr_copy(&path, s->input); dstr_replace(&path, "\\", "/"); slash = strrchr(path.array, '/'); if (slash) dstr_resize(&path, slash - path.array + 1); } obs_properties_add_path(props, "local_file", obs_module_text("LocalFile"), OBS_PATH_FILE, filter.array, path.array); dstr_free(&filter); dstr_free(&path); prop = obs_properties_add_bool(props, "looping", obs_module_text("Looping")); obs_properties_add_bool(props, "restart_on_activate", obs_module_text("RestartWhenActivated")); obs_properties_add_text(props, "input", obs_module_text("Input"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "input_format", obs_module_text("InputFormat"), OBS_TEXT_DEFAULT); #ifndef __APPLE__ obs_properties_add_bool(props, "hw_decode", obs_module_text("HardwareDecode")); #endif obs_properties_add_bool(props, "clear_on_media_end", obs_module_text("ClearOnMediaEnd")); prop = obs_properties_add_bool(props, "close_when_inactive", obs_module_text("CloseFileWhenInactive")); obs_property_set_long_description(prop, obs_module_text("CloseFileWhenInactive.ToolTip")); prop = obs_properties_add_list(props, "color_range", obs_module_text("ColorRange"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_list_add_int(prop, obs_module_text("ColorRange.Auto"), VIDEO_RANGE_DEFAULT); obs_property_list_add_int(prop, obs_module_text("ColorRange.Partial"), VIDEO_RANGE_PARTIAL); obs_property_list_add_int(prop, obs_module_text("ColorRange.Full"), VIDEO_RANGE_FULL); return props; }
static obs_properties_t *ffmpeg_source_getproperties(void *data) { struct ffmpeg_source *s = data; struct dstr filter = {0}; struct dstr path = {0}; UNUSED_PARAMETER(data); obs_properties_t *props = obs_properties_create(); obs_properties_set_flags(props, OBS_PROPERTIES_DEFER_UPDATE); obs_property_t *prop; // use this when obs allows non-readonly paths prop = obs_properties_add_bool(props, "is_local_file", obs_module_text("LocalFile")); obs_property_set_modified_callback(prop, is_local_file_modified); dstr_copy(&filter, obs_module_text("MediaFileFilter.AllMediaFiles")); dstr_cat(&filter, media_filter); dstr_cat(&filter, obs_module_text("MediaFileFilter.VideoFiles")); dstr_cat(&filter, video_filter); dstr_cat(&filter, obs_module_text("MediaFileFilter.AudioFiles")); dstr_cat(&filter, audio_filter); dstr_cat(&filter, obs_module_text("MediaFileFilter.AllFiles")); dstr_cat(&filter, " (*.*)"); if (s && s->input && *s->input) { const char *slash; dstr_copy(&path, s->input); dstr_replace(&path, "\\", "/"); slash = strrchr(path.array, '/'); if (slash) dstr_resize(&path, slash - path.array + 1); } obs_properties_add_path(props, "local_file", obs_module_text("LocalFile"), OBS_PATH_FILE, filter.array, path.array); dstr_free(&filter); dstr_free(&path); obs_properties_add_bool(props, "looping", obs_module_text("Looping")); obs_properties_add_bool(props, "restart_on_activate", obs_module_text("RestartWhenActivated")); obs_properties_add_text(props, "input", obs_module_text("Input"), OBS_TEXT_DEFAULT); obs_properties_add_text(props, "input_format", obs_module_text("InputFormat"), OBS_TEXT_DEFAULT); obs_properties_add_bool(props, "hw_decode", obs_module_text("HardwareDecode")); obs_properties_add_bool(props, "clear_on_media_end", obs_module_text("ClearOnMediaEnd")); prop = obs_properties_add_bool(props, "advanced", obs_module_text("Advanced")); obs_property_set_modified_callback(prop, is_advanced_modified); obs_properties_add_bool(props, "force_scale", obs_module_text("ForceFormat")); prop = obs_properties_add_int(props, "audio_buffer_size", obs_module_text("AudioBufferSize"), 1, 9999, 1); obs_property_set_visible(prop, false); prop = obs_properties_add_int(props, "video_buffer_size", obs_module_text("VideoBufferSize"), 1, 9999, 1); obs_property_set_visible(prop, false); prop = obs_properties_add_list(props, "frame_drop", obs_module_text("FrameDropping"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_list_add_int(prop, obs_module_text("DiscardNone"), AVDISCARD_NONE); obs_property_list_add_int(prop, obs_module_text("DiscardDefault"), AVDISCARD_DEFAULT); obs_property_list_add_int(prop, obs_module_text("DiscardNonRef"), AVDISCARD_NONREF); obs_property_list_add_int(prop, obs_module_text("DiscardBiDir"), AVDISCARD_BIDIR); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 67, 100) obs_property_list_add_int(prop, obs_module_text("DiscardNonIntra"), AVDISCARD_NONINTRA); #endif obs_property_list_add_int(prop, obs_module_text("DiscardNonKey"), AVDISCARD_NONKEY); obs_property_list_add_int(prop, obs_module_text("DiscardAll"), AVDISCARD_ALL); obs_property_set_visible(prop, false); prop = obs_properties_add_list(props, "color_range", obs_module_text("ColorRange"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_list_add_int(prop, obs_module_text("ColorRange.Auto"), VIDEO_RANGE_DEFAULT); obs_property_list_add_int(prop, obs_module_text("ColorRange.Partial"), VIDEO_RANGE_PARTIAL); obs_property_list_add_int(prop, obs_module_text("ColorRange.Full"), VIDEO_RANGE_FULL); obs_property_set_visible(prop, false); return props; }