static inline void ep_write_param(struct dstr *shader, struct ep_param *param, struct darray *used_params) { if (param->written) return; if (param->is_const) { dstr_cat(shader, "const "); } else if (param->is_uniform) { struct dstr new; dstr_init_copy(&new, param->name); darray_push_back(sizeof(struct dstr), used_params, &new); dstr_cat(shader, "uniform "); } dstr_cat(shader, param->type); dstr_cat(shader, " "); dstr_cat(shader, param->name); if (param->array_count) dstr_catf(shader, "[%u]", param->array_count); dstr_cat(shader, ";\n"); param->written = true; }
static inline void write_thread_trace(struct exception_handler_data *data, THREADENTRY32 *entry) { bool crash_thread = entry->th32ThreadID == GetCurrentThreadId(); struct stack_trace trace = {0}; struct stack_trace *ptrace; HANDLE thread; if (entry->th32OwnerProcessID != GetCurrentProcessId()) return; thread = OpenThread(THREAD_ALL_ACCESS, false, entry->th32ThreadID); if (!thread) return; trace.context.ContextFlags = CONTEXT_ALL; GetThreadContext(thread, &trace.context); init_instruction_data(&trace); dstr_catf(&data->str, "\r\nThread %lX%s\r\n"TRACE_TOP, entry->th32ThreadID, crash_thread ? " (Crashed)" : ""); ptrace = crash_thread ? &data->main_trace : &trace; while (walk_stack(data, thread, ptrace)); CloseHandle(thread); }
static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd) { obs_encoder_t *vencoder = obs_output_get_video_encoder(stream->output); obs_encoder_t *aencoders[MAX_AUDIO_MIXES]; int num_tracks = 0; for (;;) { obs_encoder_t *aencoder = obs_output_get_audio_encoder( stream->output, num_tracks); if (!aencoder) break; aencoders[num_tracks] = aencoder; num_tracks++; } dstr_init_move_array(cmd, obs_module_file(FFMPEG_MUX)); dstr_insert_ch(cmd, 0, '\"'); dstr_cat(cmd, "\" \""); dstr_cat_dstr(cmd, &stream->path); dstr_catf(cmd, "\" %d %d ", vencoder ? 1 : 0, num_tracks); if (vencoder) add_video_encoder_params(stream, cmd, vencoder); if (num_tracks) { dstr_cat(cmd, "aac "); for (int i = 0; i < num_tracks; i++) { add_audio_encoder_params(cmd, aencoders[i]); } } }
static BOOL CALLBACK enum_monitor_props(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM param) { UNUSED_PARAMETER(hdc); UNUSED_PARAMETER(rect); obs_property_t *monitor_list = (obs_property_t*)param; MONITORINFO mi; size_t monitor_id = 0; struct dstr monitor_desc = { 0 }; struct dstr resolution = { 0 }; struct dstr format_string = { 0 }; monitor_id = obs_property_list_item_count(monitor_list); mi.cbSize = sizeof(mi); GetMonitorInfo(handle, &mi); dstr_catf(&resolution, "%dx%d @ %d,%d", mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, mi.rcMonitor.left, mi.rcMonitor.top); dstr_copy(&format_string, "%s %d: %s"); if (mi.dwFlags == MONITORINFOF_PRIMARY) { dstr_catf(&format_string, " (%s)", TEXT_PRIMARY_MONITOR); } dstr_catf(&monitor_desc, format_string.array, TEXT_MONITOR, monitor_id, resolution.array); obs_property_list_add_int(monitor_list, monitor_desc.array, (int)monitor_id); dstr_free(&monitor_desc); dstr_free(&resolution); dstr_free(&format_string); return TRUE; }
static inline void write_header(struct exception_handler_data *data) { dstr_catf(&data->str, "Unhandled exception: %x\r\n" "Fault address: %"PRIX64" (%s)\r\n" "libobs version: "OBS_VERSION"\r\n" "Windows version: %d.%d build %d (revision %d)\r\n" "CPU: %s\r\n\r\n", data->exception->ExceptionRecord->ExceptionCode, data->main_trace.instruction_ptr, data->module_name.array, data->win_version.major, data->win_version.minor, data->win_version.build, data->win_version.revis, data->cpu_info.array); }
static BOOL CALLBACK enum_all_modules(PCTSTR module_name, DWORD64 module_base, ULONG module_size, struct exception_handler_data *data) { char name_utf8[MAX_PATH]; os_wcs_to_utf8(module_name, 0, name_utf8, MAX_PATH); if (data->main_trace.instruction_ptr >= module_base && data->main_trace.instruction_ptr < module_base + module_size) { dstr_copy(&data->module_name, name_utf8); strlwr(data->module_name.array); } #ifdef _WIN64 dstr_catf(&data->module_list, "%016"PRIX64"-%016"PRIX64" %s\r\n", module_base, module_base + module_size, name_utf8); #else dstr_catf(&data->module_list, "%08"PRIX64"-%08"PRIX64" %s\r\n", module_base, module_base + module_size, name_utf8); #endif return true; }
static void add_video_encoder_params(struct ffmpeg_muxer *stream, struct dstr *cmd, obs_encoder_t *vencoder) { obs_data_t *settings = obs_encoder_get_settings(vencoder); int bitrate = (int)obs_data_get_int(settings, "bitrate"); video_t *video = obs_get_video(); const struct video_output_info *info = video_output_get_info(video); obs_data_release(settings); dstr_catf(cmd, "%s %d %d %d %d %d ", "h264", bitrate, obs_output_get_width(stream->output), obs_output_get_height(stream->output), (int)info->fps_num, (int)info->fps_den); }
static bool get_monitor_props(obs_property_t *monitor_list, int monitor_idx) { struct dstr monitor_desc = {0}; struct gs_monitor_info info; if (!gs_get_duplicator_monitor_info(monitor_idx, &info)) return false; dstr_catf(&monitor_desc, "%s %d: %ldx%ld @ %ld,%ld", TEXT_MONITOR, monitor_idx, info.cx, info.cy, info.x, info.y); obs_property_list_add_int(monitor_list, monitor_desc.array, monitor_idx); dstr_free(&monitor_desc); return true; }
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); }
static inline void write_header(struct exception_handler_data *data) { char date_time[80]; time_t now = time(0); struct tm ts; ts = *localtime(&now); strftime(date_time, sizeof(date_time), "%Y-%m-%d, %X", &ts); dstr_catf(&data->str, "Unhandled exception: %x\r\n" "Date/Time: %s\r\n" "Fault address: %"PRIX64" (%s)\r\n" "libobs version: "OBS_VERSION"\r\n" "Windows version: %d.%d build %d (revision: %d; " "%s-bit)\r\n" "CPU: %s\r\n\r\n", data->exception->ExceptionRecord->ExceptionCode, date_time, data->main_trace.instruction_ptr, data->module_name.array, data->win_version.major, data->win_version.minor, data->win_version.build, data->win_version.revis, is_64_bit_windows() ? "64" : "32", data->cpu_info.array); }
static int try_connect(struct rtmp_stream *stream) { if (dstr_is_empty(&stream->path)) { warn("URL is empty"); return OBS_OUTPUT_BAD_PATH; } info("Connecting to RTMP URL %s...", stream->path.array); memset(&stream->rtmp.Link, 0, sizeof(stream->rtmp.Link)); if (!RTMP_SetupURL(&stream->rtmp, stream->path.array)) return OBS_OUTPUT_BAD_PATH; RTMP_EnableWrite(&stream->rtmp); dstr_copy(&stream->encoder_name, "FMLE/3.0 (compatible; obs-studio/"); #ifdef HAVE_OBSCONFIG_H dstr_cat(&stream->encoder_name, OBS_VERSION); #else dstr_catf(&stream->encoder_name, "%d.%d.%d", LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, LIBOBS_API_PATCH_VER); #endif dstr_cat(&stream->encoder_name, "; FMSc/1.0)"); set_rtmp_dstr(&stream->rtmp.Link.pubUser, &stream->username); set_rtmp_dstr(&stream->rtmp.Link.pubPasswd, &stream->password); set_rtmp_dstr(&stream->rtmp.Link.flashVer, &stream->encoder_name); stream->rtmp.Link.swfUrl = stream->rtmp.Link.tcUrl; RTMP_AddStream(&stream->rtmp, stream->key.array); for (size_t idx = 1;; idx++) { obs_encoder_t *encoder = obs_output_get_audio_encoder( stream->output, idx); const char *encoder_name; if (!encoder) break; encoder_name = obs_encoder_get_name(encoder); RTMP_AddStream(&stream->rtmp, encoder_name); } stream->rtmp.m_outChunkSize = 4096; stream->rtmp.m_bSendChunkSizeInfo = true; stream->rtmp.m_bUseNagle = true; #ifdef _WIN32 win32_log_interface_type(stream); #endif if (!RTMP_Connect(&stream->rtmp, NULL)) return OBS_OUTPUT_CONNECT_FAILED; if (!RTMP_ConnectStream(&stream->rtmp, 0)) return OBS_OUTPUT_INVALID_STREAM; info("Connection to %s successful", stream->path.array); return init_send(stream); }
static inline bool ep_compile_pass_shader(struct effect_parser *ep, struct gs_effect_technique *tech, struct gs_effect_pass *pass, struct ep_pass *pass_in, size_t pass_idx, enum gs_shader_type type) { struct dstr shader_str; struct dstr location; struct darray used_params; /* struct dstr */ struct darray *pass_params = NULL; /* struct pass_shaderparam */ gs_shader_t *shader = NULL; bool success = true; dstr_init(&shader_str); darray_init(&used_params); dstr_init(&location); dstr_copy(&location, ep->cfp.lex.file); if (type == GS_SHADER_VERTEX) dstr_cat(&location, " (Vertex "); else if (type == GS_SHADER_PIXEL) dstr_cat(&location, " (Pixel "); /*else if (type == SHADER_GEOMETRY) dstr_cat(&location, " (Geometry ");*/ assert(pass_idx <= UINT_MAX); dstr_catf(&location, "shader, technique %s, pass %u)", tech->name, (unsigned)pass_idx); if (type == GS_SHADER_VERTEX) { ep_makeshaderstring(ep, &shader_str, &pass_in->vertex_program.da, &used_params); pass->vertshader = gs_vertexshader_create(shader_str.array, location.array, NULL); shader = pass->vertshader; pass_params = &pass->vertshader_params.da; } else if (type == GS_SHADER_PIXEL) { ep_makeshaderstring(ep, &shader_str, &pass_in->fragment_program.da, &used_params); pass->pixelshader = gs_pixelshader_create(shader_str.array, location.array, NULL); shader = pass->pixelshader; pass_params = &pass->pixelshader_params.da; } #if 0 blog(LOG_DEBUG, "+++++++++++++++++++++++++++++++++++"); blog(LOG_DEBUG, " %s", location.array); blog(LOG_DEBUG, "-----------------------------------"); blog(LOG_DEBUG, "%s", shader_str.array); blog(LOG_DEBUG, "+++++++++++++++++++++++++++++++++++"); #endif if (shader) success = ep_compile_pass_shaderparams(ep, pass_params, &used_params, shader); else success = false; dstr_free(&location); dstr_array_free(used_params.array, used_params.num); darray_free(&used_params); dstr_free(&shader_str); return success; }
static inline bool walk_stack(struct exception_handler_data *data, HANDLE thread, struct stack_trace *trace) { struct module_info module_info = {0}; DWORD64 func_offset; char sym_name[256]; char *p; bool success = data->stack_walk64(trace->image_type, data->process, thread, &trace->frame, &trace->context, NULL, data->sym_function_table_access64, data->sym_get_module_base64, NULL); if (!success) return false; module_info.addr = trace->frame.AddrPC.Offset; get_module_name(data, &module_info); if (!!module_info.name_utf8[0]) { p = strrchr(module_info.name_utf8, '\\'); p = p ? (p + 1) : module_info.name_utf8; } else { strcpy(module_info.name_utf8, "<unknown>"); p = module_info.name_utf8; } success = !!data->sym_from_addr(data->process, trace->frame.AddrPC.Offset, &func_offset, data->sym_info); if (success) os_wcs_to_utf8(data->sym_info->Name, 0, sym_name, 256); #ifdef _WIN64 #define SUCCESS_FORMAT \ "%016I64X %016I64X %016I64X %016I64X " \ "%016I64X %016I64X %s!%s+0x%I64x\r\n" #define FAIL_FORMAT \ "%016I64X %016I64X %016I64X %016I64X " \ "%016I64X %016I64X %s!0x%I64x\r\n" #else #define SUCCESS_FORMAT \ "%08.8I64X %08.8I64X %08.8I64X %08.8I64X " \ "%08.8I64X %08.8I64X %s!%s+0x%I64x\r\n" #define FAIL_FORMAT \ "%08.8I64X %08.8I64X %08.8I64X %08.8I64X " \ "%08.8I64X %08.8I64X %s!0x%I64x\r\n" trace->frame.AddrStack.Offset &= 0xFFFFFFFFF; trace->frame.AddrPC.Offset &= 0xFFFFFFFFF; trace->frame.Params[0] &= 0xFFFFFFFF; trace->frame.Params[1] &= 0xFFFFFFFF; trace->frame.Params[2] &= 0xFFFFFFFF; trace->frame.Params[3] &= 0xFFFFFFFF; #endif if (success && (data->sym_info->Flags & SYMFLAG_EXPORT) == 0) { dstr_catf(&data->str, SUCCESS_FORMAT, trace->frame.AddrStack.Offset, trace->frame.AddrPC.Offset, trace->frame.Params[0], trace->frame.Params[1], trace->frame.Params[2], trace->frame.Params[3], p, sym_name, func_offset); } else { dstr_catf(&data->str, FAIL_FORMAT, trace->frame.AddrStack.Offset, trace->frame.AddrPC.Offset, trace->frame.Params[0], trace->frame.Params[1], trace->frame.Params[2], trace->frame.Params[3], p, trace->frame.AddrPC.Offset); } return true; }
static bool build_flv_meta_data(obs_output_t *context, uint8_t **output, size_t *size, size_t a_idx) { obs_encoder_t *vencoder = obs_output_get_video_encoder(context); obs_encoder_t *aencoder = obs_output_get_audio_encoder(context, a_idx); video_t *video = obs_encoder_video(vencoder); audio_t *audio = obs_encoder_audio(aencoder); char buf[4096]; char *enc = buf; char *end = enc+sizeof(buf); struct dstr encoder_name = {0}; if (a_idx > 0 && !aencoder) return false; enc_str(&enc, end, "onMetaData"); *enc++ = AMF_ECMA_ARRAY; enc = AMF_EncodeInt32(enc, end, a_idx == 0 ? 14 : 9); enc_num_val(&enc, end, "duration", 0.0); enc_num_val(&enc, end, "fileSize", 0.0); if (a_idx == 0) { enc_num_val(&enc, end, "width", (double)obs_encoder_get_width(vencoder)); enc_num_val(&enc, end, "height", (double)obs_encoder_get_height(vencoder)); enc_str_val(&enc, end, "videocodecid", "avc1"); enc_num_val(&enc, end, "videodatarate", encoder_bitrate(vencoder)); enc_num_val(&enc, end, "framerate", video_output_get_frame_rate(video)); } enc_str_val(&enc, end, "audiocodecid", "mp4a"); enc_num_val(&enc, end, "audiodatarate", encoder_bitrate(aencoder)); enc_num_val(&enc, end, "audiosamplerate", (double)obs_encoder_get_sample_rate(aencoder)); enc_num_val(&enc, end, "audiosamplesize", 16.0); enc_num_val(&enc, end, "audiochannels", (double)audio_output_get_channels(audio)); enc_bool_val(&enc, end, "stereo", audio_output_get_channels(audio) == 2); enc_bool_val(&enc, end, "2.1", audio_output_get_channels(audio) == 3); enc_bool_val(&enc, end, "3.1", audio_output_get_channels(audio) == 4); enc_bool_val(&enc, end, "4.0", audio_output_get_channels(audio) == 4); enc_bool_val(&enc, end, "4.1", audio_output_get_channels(audio) == 5); enc_bool_val(&enc, end, "5.1", audio_output_get_channels(audio) == 6); enc_bool_val(&enc, end, "7.1", audio_output_get_channels(audio) == 8); dstr_printf(&encoder_name, "%s (libobs version ", MODULE_NAME); #ifdef HAVE_OBSCONFIG_H dstr_cat(&encoder_name, OBS_VERSION); #else dstr_catf(&encoder_name, "%d.%d.%d", LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, LIBOBS_API_PATCH_VER); #endif dstr_cat(&encoder_name, ")"); enc_str_val(&enc, end, "encoder", encoder_name.array); dstr_free(&encoder_name); *enc++ = 0; *enc++ = 0; *enc++ = AMF_OBJECT_END; *size = enc-buf; *output = bmemdup(buf, *size); return true; }