static void image_source_update(void *data, obs_data_t *settings) { struct image_source *context = data; const char *file = obs_data_get_string(settings, "file"); const bool unload = obs_data_get_bool(settings, "unload"); if (context->file) bfree(context->file); context->file = bstrdup(file); context->persistent = !unload; /* Load the image if the source is persistent or showing */ if (context->persistent || obs_source_showing(context->source)) image_source_load(data); else image_source_unload(data); }
static void scene_load_item(struct obs_scene *scene, obs_data_t *item_data) { const char *name = obs_data_get_string(item_data, "name"); obs_source_t *source = obs_get_source_by_name(name); struct obs_scene_item *item; bool visible; if (!source) { blog(LOG_WARNING, "[scene_load_item] Source %s not found!", name); return; } item = obs_scene_add(scene, source); if (!item) { blog(LOG_WARNING, "[scene_load_item] Could not add source '%s' " "to scene '%s'!", name, obs_source_get_name(scene->source)); obs_source_release(source); return; } obs_data_set_default_int(item_data, "align", OBS_ALIGN_TOP | OBS_ALIGN_LEFT); item->rot = (float)obs_data_get_double(item_data, "rot"); item->align = (uint32_t)obs_data_get_int(item_data, "align"); visible = obs_data_get_bool(item_data, "visible"); obs_data_get_vec2(item_data, "pos", &item->pos); obs_data_get_vec2(item_data, "scale", &item->scale); set_visibility(item, visible); item->bounds_type = (enum obs_bounds_type)obs_data_get_int(item_data, "bounds_type"); item->bounds_align = (uint32_t)obs_data_get_int(item_data, "bounds_align"); obs_data_get_vec2(item_data, "bounds", &item->bounds); obs_source_release(source); update_item_transform(item); }
static bool is_local_file_modified(obs_properties_t *props, obs_property_t *prop, obs_data_t *settings) { UNUSED_PARAMETER(prop); bool enabled = obs_data_get_bool(settings, "is_local_file"); obs_property_t *input = obs_properties_get(props, "input"); obs_property_t *input_format =obs_properties_get(props, "input_format"); obs_property_t *local_file = obs_properties_get(props, "local_file"); obs_property_t *looping = obs_properties_get(props, "looping"); obs_property_set_visible(input, !enabled); obs_property_set_visible(input_format, !enabled); obs_property_set_visible(local_file, enabled); obs_property_set_visible(looping, enabled); return true; }
static bool relative_clicked(obs_properties_t *props, obs_property_t *p, obs_data_t *settings) { bool relative = obs_data_get_bool(settings, "relative"); obs_property_set_description(obs_properties_get(props, "left"), relative ? obs_module_text("Crop.Left") : "X"); obs_property_set_description(obs_properties_get(props, "top"), relative ? obs_module_text("Crop.Top") : "Y"); obs_property_set_visible(obs_properties_get(props, "right"), relative); obs_property_set_visible(obs_properties_get(props, "bottom"), relative); obs_property_set_visible(obs_properties_get(props, "cx"), !relative); obs_property_set_visible(obs_properties_get(props, "cy"), !relative); UNUSED_PARAMETER(p); return true; }
static bool is_advanced_modified(obs_properties_t *props, obs_property_t *prop, obs_data_t *settings) { UNUSED_PARAMETER(prop); bool enabled = obs_data_get_bool(settings, "advanced"); obs_property_t *fscale = obs_properties_get(props, "force_scale"); obs_property_t *abuf = obs_properties_get(props, "audio_buffer_size"); obs_property_t *vbuf = obs_properties_get(props, "video_buffer_size"); obs_property_t *frame_drop = obs_properties_get(props, "frame_drop"); obs_property_t *color_range = obs_properties_get(props, "color_range"); obs_property_set_visible(fscale, enabled); obs_property_set_visible(abuf, enabled); obs_property_set_visible(vbuf, enabled); obs_property_set_visible(frame_drop, enabled); obs_property_set_visible(color_range, enabled); return true; }
static inline void update_settings(struct duplicator_capture *capture, obs_data_t *settings) { capture->monitor = (int)obs_data_get_int(settings, "monitor"); capture->capture_cursor = obs_data_get_bool(settings, "capture_cursor"); obs_enter_graphics(); gs_duplicator_destroy(capture->duplicator); capture->duplicator = gs_duplicator_create(capture->monitor); capture->width = 0; capture->height = 0; capture->x = 0; capture->y = 0; capture->rot = 0; capture->reset_timeout = 0.0f; obs_leave_graphics(); }
static void decklink_update(void *data, obs_data_t *settings) { DeckLink *decklink = (DeckLink *)data; const char *hash = obs_data_get_string(settings, DEVICE_HASH); long long id = obs_data_get_int(settings, MODE_ID); BMDPixelFormat pixelFormat = (BMDPixelFormat)obs_data_get_int(settings, PIXEL_FORMAT); speaker_layout channelFormat = (speaker_layout)obs_data_get_int(settings, CHANNEL_FORMAT); decklink_enable_buffering(decklink, obs_data_get_bool(settings, BUFFERING)); ComPtr<DeckLinkDevice> device; device.Set(deviceEnum->FindByHash(hash)); decklink->SetPixelFormat(pixelFormat); decklink->SetChannelFormat(channelFormat); decklink->Activate(device, id); }
/** * Update the settings for the v4l2 source * * Since there are very few settings that can be changed without restarting the * stream we don't bother to even try. Whenever this is called the currently * active stream (if exists) is stopped, the settings are updated and finally * the new stream is started. */ static void v4l2_update(void *vptr, obs_data_t *settings) { V4L2_DATA(vptr); v4l2_terminate(data); if (data->device_id) bfree(data->device_id); data->device_id = bstrdup(obs_data_get_string(settings, "device_id")); data->input = obs_data_get_int(settings, "input"); data->pixfmt = obs_data_get_int(settings, "pixelformat"); data->standard = obs_data_get_int(settings, "standard"); data->dv_timing = obs_data_get_int(settings, "dv_timing"); data->resolution = obs_data_get_int(settings, "resolution"); data->framerate = obs_data_get_int(settings, "framerate"); data->sys_timing = obs_data_get_bool(settings, "system_timing"); v4l2_init(data); }
/** * Update the capture with changed settings */ static void xshm_update(void *vptr, obs_data_t settings) { XSHM_DATA(vptr); data->show_cursor = obs_data_get_bool(settings, "show_cursor"); if (data->xshm) xshm_detach(data->xshm); if (xshm_update_geometry(data, settings) < 0) { blog(LOG_ERROR, "xshm-input: failed to update geometry !"); return; } xshm_resize_texture(data); xcursor_offset(data->cursor, data->x_org, data->y_org); data->xshm = xshm_attach(data->dpy, data->screen, data->width, data->height); if (!data->xshm) { blog(LOG_ERROR, "xshm-input: failed to attach shm !"); return; } }
static void ffmpeg_source_update(void *data, obs_data_t *settings) { struct ffmpeg_source *s = data; bool is_local_file = obs_data_get_bool(settings, "is_local_file"); bool is_advanced = obs_data_get_bool(settings, "advanced"); char *input; char *input_format; bfree(s->input); bfree(s->input_format); if (is_local_file) { input = (char *)obs_data_get_string(settings, "local_file"); input_format = NULL; s->is_looping = obs_data_get_bool(settings, "looping"); } else { input = (char *)obs_data_get_string(settings, "input"); input_format = (char *)obs_data_get_string(settings, "input_format"); s->is_looping = false; } s->input = input ? bstrdup(input) : NULL; s->input_format = input_format ? bstrdup(input_format) : NULL; s->is_advanced = is_advanced; s->is_hw_decoding = obs_data_get_bool(settings, "hw_decode"); s->is_clear_on_media_end = obs_data_get_bool(settings, "clear_on_media_end"); s->restart_on_activate = obs_data_get_bool(settings, "restart_on_activate"); s->is_forcing_scale = true; if (is_advanced) { s->audio_buffer_size = (int)obs_data_get_int(settings, "audio_buffer_size"); s->video_buffer_size = (int)obs_data_get_int(settings, "video_buffer_size"); s->frame_drop = (enum AVDiscard)obs_data_get_int(settings, "frame_drop"); s->is_forcing_scale = obs_data_get_bool(settings, "force_scale"); if (s->audio_buffer_size < 1) { s->audio_buffer_size = 1; FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d", s->audio_buffer_size); } if (s->video_buffer_size < 1) { s->video_buffer_size = 1; FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d", s->audio_buffer_size); } if (s->frame_drop < AVDISCARD_NONE || s->frame_drop > AVDISCARD_ALL) { s->frame_drop = AVDISCARD_DEFAULT; FF_BLOG(LOG_WARNING, "invalid frame_drop %d", s->frame_drop); } } dump_source_info(s, input, input_format, is_advanced); if (!s->restart_on_activate || obs_source_active(s->source)) ffmpeg_source_start(s); }
static void update_params(struct obs_qsv *obsqsv, obs_data_t *settings) { video_t *video = obs_encoder_video(obsqsv->encoder); const struct video_output_info *voi = video_output_get_info(video); const char *target_usage = obs_data_get_string(settings, "target_usage"); const char *profile = obs_data_get_string(settings, "profile"); const char *rate_control = obs_data_get_string(settings, "rate_control"); int async_depth = (int)obs_data_get_int(settings, "async_depth"); int target_bitrate = (int)obs_data_get_int(settings, "bitrate"); int max_bitrate = (int)obs_data_get_int(settings, "max_bitrate"); int accuracy = (int)obs_data_get_int(settings, "accuracy"); int convergence = (int)obs_data_get_int(settings, "convergence"); int qpi = (int)obs_data_get_int(settings, "qpi"); int qpp = (int)obs_data_get_int(settings, "qpp"); int qpb = (int)obs_data_get_int(settings, "qpb"); int icq_quality = (int)obs_data_get_int(settings, "icq_quality"); int la_depth = (int)obs_data_get_int(settings, "la_depth"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); bool cbr_override = obs_data_get_bool(settings, "cbr"); int bFrames = 7; int width = (int)obs_encoder_get_width(obsqsv->encoder); int height = (int)obs_encoder_get_height(obsqsv->encoder); if (astrcmpi(target_usage, "quality") == 0) obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_BEST_QUALITY; else if (astrcmpi(target_usage, "balanced") == 0) obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_BALANCED; else if (astrcmpi(target_usage, "speed") == 0) obsqsv->params.nTargetUsage = MFX_TARGETUSAGE_BEST_SPEED; if (astrcmpi(profile, "baseline") == 0) obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_BASELINE; else if (astrcmpi(profile, "main") == 0) obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_MAIN; else if (astrcmpi(profile, "high") == 0) obsqsv->params.nCodecProfile = MFX_PROFILE_AVC_HIGH; /* internal convenience parameter, overrides rate control param * XXX: Deprecated */ if (cbr_override) { warn("\"cbr\" setting has been deprecated for all encoders! " "Please set \"rate_control\" to \"CBR\" instead. " "Forcing CBR mode. " "(Note to all: this is why you shouldn't use strings for " "common settings)"); rate_control = "CBR"; } if (astrcmpi(rate_control, "CBR") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_CBR; else if (astrcmpi(rate_control, "VBR") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_VBR; else if (astrcmpi(rate_control, "VCM") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_VCM; else if (astrcmpi(rate_control, "CQP") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_CQP; else if (astrcmpi(rate_control, "AVBR") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_AVBR; else if (astrcmpi(rate_control, "ICQ") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_ICQ; else if (astrcmpi(rate_control, "LA_ICQ") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_LA_ICQ; else if (astrcmpi(rate_control, "LA") == 0) obsqsv->params.nRateControl = MFX_RATECONTROL_LA; obsqsv->params.nAsyncDepth = (mfxU16)async_depth; obsqsv->params.nAccuracy = (mfxU16)accuracy; obsqsv->params.nConvergence = (mfxU16)convergence; obsqsv->params.nQPI = (mfxU16)qpi; obsqsv->params.nQPP = (mfxU16)qpp; obsqsv->params.nQPB = (mfxU16)qpb; obsqsv->params.nLADEPTH = (mfxU16)la_depth; obsqsv->params.nTargetBitRate = (mfxU16)target_bitrate; obsqsv->params.nMaxBitRate = (mfxU16)max_bitrate; obsqsv->params.nWidth = (mfxU16)width; obsqsv->params.nHeight = (mfxU16)height; obsqsv->params.nFpsNum = (mfxU16)voi->fps_num; obsqsv->params.nFpsDen = (mfxU16)voi->fps_den; obsqsv->params.nbFrames = (mfxU16)bFrames; obsqsv->params.nKeyIntSec = (mfxU16)keyint_sec; obsqsv->params.nICQQuality = (mfxU16)icq_quality; info("settings:\n\trate_control: %s", rate_control); if (obsqsv->params.nRateControl != MFX_RATECONTROL_LA_ICQ && obsqsv->params.nRateControl != MFX_RATECONTROL_ICQ && obsqsv->params.nRateControl != MFX_RATECONTROL_CQP) blog(LOG_INFO, "\ttarget_bitrate: %d", (int)obsqsv->params.nTargetBitRate); if (obsqsv->params.nRateControl == MFX_RATECONTROL_VBR || obsqsv->params.nRateControl == MFX_RATECONTROL_VCM) blog(LOG_INFO, "\tmax_bitrate: %d", (int)obsqsv->params.nMaxBitRate); if (obsqsv->params.nRateControl == MFX_RATECONTROL_LA_ICQ || obsqsv->params.nRateControl == MFX_RATECONTROL_ICQ) blog(LOG_INFO, "\tICQ Quality: %d", (int)obsqsv->params.nICQQuality); if (obsqsv->params.nRateControl == MFX_RATECONTROL_LA_ICQ || obsqsv->params.nRateControl == MFX_RATECONTROL_LA) blog(LOG_INFO, "\tLookahead Depth:%d", (int)obsqsv->params.nLADEPTH); if (obsqsv->params.nRateControl == MFX_RATECONTROL_CQP) blog(LOG_INFO, "\tqpi: %d\n" "\tqpb: %d\n" "\tqpp: %d", qpi, qpb, qpp); blog(LOG_INFO, "\tfps_num: %d\n" "\tfps_den: %d\n" "\twidth: %d\n" "\theight: %d", voi->fps_num, voi->fps_den, width, height); info("debug info:"); }
void XCompcapMain::updateSettings(obs_data_t *settings) { PLock lock(&p->lock); XErrorLock xlock; ObsGsContextHolder obsctx; blog(LOG_DEBUG, "Settings updating"); Window prevWin = p->win; xcc_cleanup(p); if (settings) { const char *windowName = obs_data_get_string(settings, "capture_window"); p->windowName = windowName; p->win = getWindowFromString(windowName); p->cut_top = obs_data_get_int(settings, "cut_top"); p->cut_left = obs_data_get_int(settings, "cut_left"); p->cut_right = obs_data_get_int(settings, "cut_right"); p->cut_bot = obs_data_get_int(settings, "cut_bot"); p->lockX = obs_data_get_bool(settings, "lock_x"); p->swapRedBlue = obs_data_get_bool(settings, "swap_redblue"); p->show_cursor = obs_data_get_bool(settings, "show_cursor"); p->include_border = obs_data_get_bool(settings, "include_border"); p->exclude_alpha = obs_data_get_bool(settings, "exclude_alpha"); } else { p->win = prevWin; } xlock.resetError(); if (p->win) XCompositeRedirectWindow(xdisp, p->win, CompositeRedirectAutomatic); if (xlock.gotError()) { blog(LOG_ERROR, "XCompositeRedirectWindow failed: %s", xlock.getErrorText().c_str()); return; } if (p->win) XSelectInput(xdisp, p->win, StructureNotifyMask | ExposureMask); XSync(xdisp, 0); XWindowAttributes attr; if (!p->win || !XGetWindowAttributes(xdisp, p->win, &attr)) { p->win = 0; p->width = 0; p->height = 0; return; } if (p->win && p->cursor && p->show_cursor) { Window child; int x, y; XTranslateCoordinates(xdisp, p->win, attr.root, 0, 0, &x, &y, &child); xcursor_offset(p->cursor, x, y); } gs_color_format cf = GS_RGBA; if (p->exclude_alpha) { cf = GS_BGRX; } p->border = attr.border_width; if (p->include_border) { p->width = attr.width + p->border * 2; p->height = attr.height + p->border * 2; } else { p->width = attr.width; p->height = attr.height; } if (p->cut_top + p->cut_bot < (int)p->height) { p->cur_cut_top = p->cut_top; p->cur_cut_bot = p->cut_bot; } else { p->cur_cut_top = 0; p->cur_cut_bot = 0; } if (p->cut_left + p->cut_right < (int)p->width) { p->cur_cut_left = p->cut_left; p->cur_cut_right = p->cut_right; } else { p->cur_cut_left = 0; p->cur_cut_right = 0; } if (p->tex) gs_texture_destroy(p->tex); uint8_t *texData = new uint8_t[width() * height() * 4]; memset(texData, 0, width() * height() * 4); const uint8_t* texDataArr[] = { texData, 0 }; p->tex = gs_texture_create(width(), height(), cf, 1, texDataArr, 0); delete[] texData; if (p->swapRedBlue) { GLuint tex = *(GLuint*)gs_texture_get_obj(p->tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glBindTexture(GL_TEXTURE_2D, 0); } const int attrs[] = { GLX_BIND_TO_TEXTURE_RGBA_EXT, GL_TRUE, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, GLX_DOUBLEBUFFER, GL_FALSE, None }; int nelem = 0; GLXFBConfig* configs = glXChooseFBConfig(xdisp, XCompcap::getRootWindowScreen(attr.root), attrs, &nelem); if (nelem <= 0) { blog(LOG_ERROR, "no matching fb config found"); p->win = 0; p->height = 0; p->width = 0; return; } glXGetFBConfigAttrib(xdisp, configs[0], GLX_Y_INVERTED_EXT, &nelem); p->inverted = nelem != 0; xlock.resetError(); p->pixmap = XCompositeNameWindowPixmap(xdisp, p->win); if (xlock.gotError()) { blog(LOG_ERROR, "XCompositeNameWindowPixmap failed: %s", xlock.getErrorText().c_str()); p->pixmap = 0; XFree(configs); return; } const int attribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, None }; p->glxpixmap = glXCreatePixmap(xdisp, configs[0], p->pixmap, attribs); if (xlock.gotError()) { blog(LOG_ERROR, "glXCreatePixmap failed: %s", xlock.getErrorText().c_str()); XFreePixmap(xdisp, p->pixmap); XFree(configs); p->pixmap = 0; p->glxpixmap = 0; return; } XFree(configs); p->gltex = gs_texture_create(p->width, p->height, cf, 1, 0, GS_GL_DUMMYTEX); GLuint gltex = *(GLuint*)gs_texture_get_obj(p->gltex); glBindTexture(GL_TEXTURE_2D, gltex); glXBindTexImageEXT(xdisp, p->glxpixmap, GLX_FRONT_LEFT_EXT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }
/** Update source flags depending on the settings */ static void v4l2_update_source_flags(struct v4l2_data *data, obs_data_t *settings) { obs_source_set_async_unbuffered(data->source, !obs_data_get_bool(settings, "buffering")); }
/** * The x server was changed */ static bool xshm_server_changed(obs_properties_t *props, obs_property_t *p, obs_data_t *settings) { UNUSED_PARAMETER(p); bool advanced = obs_data_get_bool(settings, "advanced"); int_fast32_t old_screen = obs_data_get_int(settings, "screen"); const char *server = obs_data_get_string(settings, "server"); obs_property_t *screens = obs_properties_get(props, "screen"); /* we want a real NULL here in case there is no string here */ server = (advanced && *server) ? server : NULL; obs_property_list_clear(screens); xcb_connection_t *xcb = xcb_connect(server, NULL); if (!xcb || xcb_connection_has_error(xcb)) { obs_property_set_enabled(screens, false); return true; } struct dstr screen_info; dstr_init(&screen_info); bool xinerama = xinerama_is_active(xcb); int_fast32_t count = (xinerama) ? xinerama_screen_count(xcb) : xcb_setup_roots_length(xcb_get_setup(xcb)); for (int_fast32_t i = 0; i < count; ++i) { int_fast32_t x, y, w, h; x = y = w = h = 0; if (xinerama) xinerama_screen_geo(xcb, i, &x, &y, &w, &h); else x11_screen_geo(xcb, i, &w, &h); dstr_printf(&screen_info, "Screen %"PRIuFAST32" (%"PRIuFAST32 "x%"PRIuFAST32" @ %"PRIuFAST32 ",%"PRIuFAST32")", i, w, h, x, y); obs_property_list_add_int(screens, screen_info.array, i); } /* handle missing screen */ if (old_screen + 1 > count) { dstr_printf(&screen_info, "Screen %"PRIuFAST32" (not found)", old_screen); size_t index = obs_property_list_add_int(screens, screen_info.array, old_screen); obs_property_list_item_disable(screens, index, true); } dstr_free(&screen_info); xcb_disconnect(xcb); obs_property_set_enabled(screens, true); return true; }
static void scene_load_item(struct obs_scene *scene, obs_data_t *item_data) { const char *name = obs_data_get_string(item_data, "name"); obs_source_t *source = obs_get_source_by_name(name); const char *scale_filter_str; struct obs_scene_item *item; bool visible; if (!source) { blog(LOG_WARNING, "[scene_load_item] Source %s not found!", name); return; } item = obs_scene_add(scene, source); if (!item) { blog(LOG_WARNING, "[scene_load_item] Could not add source '%s' " "to scene '%s'!", name, obs_source_get_name(scene->source)); obs_source_release(source); return; } obs_data_set_default_int(item_data, "align", OBS_ALIGN_TOP | OBS_ALIGN_LEFT); item->rot = (float)obs_data_get_double(item_data, "rot"); item->align = (uint32_t)obs_data_get_int(item_data, "align"); visible = obs_data_get_bool(item_data, "visible"); obs_data_get_vec2(item_data, "pos", &item->pos); obs_data_get_vec2(item_data, "scale", &item->scale); set_visibility(item, visible); item->bounds_type = (enum obs_bounds_type)obs_data_get_int(item_data, "bounds_type"); item->bounds_align = (uint32_t)obs_data_get_int(item_data, "bounds_align"); obs_data_get_vec2(item_data, "bounds", &item->bounds); item->crop.left = (uint32_t)obs_data_get_int(item_data, "crop_left"); item->crop.top = (uint32_t)obs_data_get_int(item_data, "crop_top"); item->crop.right = (uint32_t)obs_data_get_int(item_data, "crop_right"); item->crop.bottom = (uint32_t)obs_data_get_int(item_data, "crop_bottom"); scale_filter_str = obs_data_get_string(item_data, "scale_filter"); item->scale_filter = OBS_SCALE_DISABLE; if (scale_filter_str) { if (astrcmpi(scale_filter_str, "point") == 0) item->scale_filter = OBS_SCALE_POINT; else if (astrcmpi(scale_filter_str, "bilinear") == 0) item->scale_filter = OBS_SCALE_BILINEAR; else if (astrcmpi(scale_filter_str, "bicubic") == 0) item->scale_filter = OBS_SCALE_BICUBIC; else if (astrcmpi(scale_filter_str, "lanczos") == 0) item->scale_filter = OBS_SCALE_LANCZOS; } if (item->item_render && !item_texture_enabled(item)) { obs_enter_graphics(); gs_texrender_destroy(item->item_render); item->item_render = NULL; obs_leave_graphics(); } else if (!item->item_render && item_texture_enabled(item)) { obs_enter_graphics(); item->item_render = gs_texrender_create(GS_RGBA, GS_ZS_NONE); obs_leave_graphics(); } obs_source_release(source); update_item_transform(item); }
static void *libfdk_create(obs_data_t settings, obs_encoder_t encoder) { bool hasFdkHandle = false; libfdk_encoder_t *enc = 0; int bitrate = (int)obs_data_get_int(settings, "bitrate") * 1000; int afterburner = obs_data_get_bool(settings, "afterburner") ? 1 : 0; audio_t audio = obs_encoder_audio(encoder); int mode = 0; AACENC_ERROR err; if (!bitrate) { blog(LOG_ERROR, "Invalid bitrate"); return NULL; } enc = bzalloc(sizeof(libfdk_encoder_t)); enc->encoder = encoder; enc->channels = (int)audio_output_get_channels(audio); enc->sample_rate = audio_output_get_sample_rate(audio); switch(enc->channels) { case 1: mode = MODE_1; break; case 2: mode = MODE_2; break; case 3: mode = MODE_1_2; break; case 4: mode = MODE_1_2_1; break; case 5: mode = MODE_1_2_2; break; case 6: mode = MODE_1_2_2_1; break; default: blog(LOG_ERROR, "Invalid channel count"); goto fail; } CHECK_LIBFDK(aacEncOpen(&enc->fdkhandle, 0, enc->channels)); hasFdkHandle = true; CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AOT, 2)); // MPEG-4 AAC-LC CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_SAMPLERATE, enc->sample_rate)); CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELMODE, mode)); CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_CHANNELORDER, 1)); CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATEMODE, 0)); CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_BITRATE, bitrate)); CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_TRANSMUX, 0)); CHECK_LIBFDK(aacEncoder_SetParam(enc->fdkhandle, AACENC_AFTERBURNER, afterburner)); CHECK_LIBFDK(aacEncEncode(enc->fdkhandle, NULL, NULL, NULL, NULL)); CHECK_LIBFDK(aacEncInfo(enc->fdkhandle, &enc->info)); enc->frame_size_bytes = enc->info.frameLength * 2 * enc->channels; enc->packet_buffer_size = enc->channels * 768; if(enc->packet_buffer_size < 8192) enc->packet_buffer_size = 8192; enc->packet_buffer = bmalloc(enc->packet_buffer_size); blog(LOG_INFO, "libfdk_aac encoder created"); blog(LOG_INFO, "libfdk_aac bitrate: %d, channels: %d", bitrate / 1000, enc->channels); return enc; fail: if(hasFdkHandle) aacEncClose(&enc->fdkhandle); if(enc->packet_buffer) bfree(enc->packet_buffer); if(enc) bfree(enc); blog(LOG_WARNING, "libfdk_aac encoder creation failed"); return 0; }
static inline void load_modifier(uint32_t *modifiers, obs_data_t *data, const char *name, uint32_t flag) { if (obs_data_get_bool(data, name)) *modifiers |= flag; }
static void ffmpeg_source_update(void *data, obs_data_t *settings) { struct ffmpeg_source *s = data; bool is_local_file = obs_data_get_bool(settings, "is_local_file"); bool is_advanced = obs_data_get_bool(settings, "advanced"); bool is_looping; char *input; char *input_format; if (is_local_file) { input = (char *)obs_data_get_string(settings, "local_file"); input_format = NULL; is_looping = obs_data_get_bool(settings, "looping"); } else { input = (char *)obs_data_get_string(settings, "input"); input_format = (char *)obs_data_get_string(settings, "input_format"); is_looping = false; } s->is_forcing_scale = obs_data_get_bool(settings, "force_scale"); s->is_hw_decoding = obs_data_get_bool(settings, "hw_decode"); s->is_clear_on_media_end = obs_data_get_bool(settings, "clear_on_media_end"); if (s->demuxer != NULL) ff_demuxer_free(s->demuxer); s->demuxer = ff_demuxer_init(); s->demuxer->options.is_hw_decoding = s->is_hw_decoding; s->demuxer->options.is_looping = is_looping; if (is_advanced) { int audio_buffer_size = (int)obs_data_get_int(settings, "audio_buffer_size"); int video_buffer_size = (int)obs_data_get_int(settings, "video_buffer_size"); enum AVDiscard frame_drop = (enum AVDiscard)obs_data_get_int(settings, "frame_drop"); if (audio_buffer_size < 1) { audio_buffer_size = 1; FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d", audio_buffer_size); } if (video_buffer_size < 1) { video_buffer_size = 1; FF_BLOG(LOG_WARNING, "invalid audio_buffer_size %d", audio_buffer_size); } s->demuxer->options.audio_frame_queue_size = audio_buffer_size; s->demuxer->options.video_frame_queue_size = video_buffer_size; if (frame_drop < AVDISCARD_NONE || frame_drop > AVDISCARD_ALL) { frame_drop = AVDISCARD_NONE; FF_BLOG(LOG_WARNING, "invalid frame_drop %d", frame_drop); } s->demuxer->options.frame_drop = frame_drop; } ff_demuxer_set_callbacks(&s->demuxer->video_callbacks, video_frame, NULL, NULL, NULL, NULL, s); ff_demuxer_set_callbacks(&s->demuxer->audio_callbacks, audio_frame, NULL, NULL, NULL, NULL, s); dump_source_info(s, input, input_format, is_advanced); ff_demuxer_open(s->demuxer, input, input_format); }
void OBSProjector::UpdateMultiview() { multiviewScenes.clear(); multiviewLabels.clear(); struct obs_video_info ovi; obs_get_video_info(&ovi); uint32_t w = ovi.base_width; uint32_t h = ovi.base_height; fw = float(w); fh = float(h); ratio = fw / fh; struct obs_frontend_source_list scenes = {}; obs_frontend_get_scenes(&scenes); multiviewLabels.emplace_back(CreateLabel(Str("StudioMode.Preview"), h / 2)); multiviewLabels.emplace_back(CreateLabel(Str("StudioMode.Program"), h / 2)); multiviewLayout = static_cast<MultiviewLayout>(config_get_int( GetGlobalConfig(), "BasicWindow", "MultiviewLayout")); drawLabel = config_get_bool(GetGlobalConfig(), "BasicWindow", "MultiviewDrawNames"); drawSafeArea = config_get_bool(GetGlobalConfig(), "BasicWindow", "MultiviewDrawAreas"); mouseSwitching = config_get_bool(GetGlobalConfig(), "BasicWindow", "MultiviewMouseSwitch"); transitionOnDoubleClick = config_get_bool(GetGlobalConfig(), "BasicWindow", "TransitionOnDoubleClick"); switch(multiviewLayout) { case MultiviewLayout::HORIZONTAL_TOP_24_SCENES: pvwprgCX = fw / 3; pvwprgCY = fh / 3; maxSrcs = 24; break; default: pvwprgCX = fw / 2; pvwprgCY = fh / 2; maxSrcs = 8; } ppiCX = pvwprgCX - thicknessx2; ppiCY = pvwprgCY - thicknessx2; ppiScaleX = (pvwprgCX - thicknessx2) / fw; ppiScaleY = (pvwprgCY - thicknessx2) / fh; scenesCX = pvwprgCX / 2; scenesCY = pvwprgCY / 2; siCX = scenesCX - thicknessx2; siCY = scenesCY - thicknessx2; siScaleX = (scenesCX - thicknessx2) / fw; siScaleY = (scenesCY - thicknessx2) / fh; numSrcs = 0; size_t i = 0; while (i < scenes.sources.num && numSrcs < maxSrcs) { obs_source_t *src = scenes.sources.array[i++]; OBSData data = obs_source_get_private_settings(src); obs_data_release(data); obs_data_set_default_bool(data, "show_in_multiview", true); if (!obs_data_get_bool(data, "show_in_multiview")) continue; // We have a displayable source. numSrcs++; multiviewScenes.emplace_back(OBSGetWeakRef(src)); obs_source_inc_showing(src); std::string name = std::to_string(numSrcs) + " - " + obs_source_get_name(src); multiviewLabels.emplace_back(CreateLabel(name.c_str(), h / 3)); } obs_frontend_source_list_free(&scenes); }
static void ft2_source_update(void *data, obs_data_t settings) { struct ft2_source *srcdata = data; obs_data_t font_obj = obs_data_get_obj(settings, "font"); bool vbuf_needs_update = false; bool word_wrap = false; uint32_t color[2]; uint32_t custom_width = 0; const char *font_name = obs_data_get_string(font_obj, "face"); const char *font_style = obs_data_get_string(font_obj, "style"); uint16_t font_size = (uint16_t)obs_data_get_int(font_obj, "size"); uint32_t font_flags = (uint32_t)obs_data_get_int(font_obj, "flags"); if (!font_obj) return; srcdata->drop_shadow = obs_data_get_bool(settings, "drop_shadow"); srcdata->outline_text = obs_data_get_bool(settings, "outline"); word_wrap = obs_data_get_bool(settings, "word_wrap"); color[0] = (uint32_t)obs_data_get_int(settings, "color1"); color[1] = (uint32_t)obs_data_get_int(settings, "color2"); custom_width = (uint32_t)obs_data_get_int(settings, "custom_width"); if (custom_width >= 100) { if (custom_width != srcdata->custom_width) { srcdata->custom_width = custom_width; vbuf_needs_update = true; } } else { if (srcdata->custom_width >= 100) vbuf_needs_update = true; srcdata->custom_width = 0; } if (word_wrap != srcdata->word_wrap) { srcdata->word_wrap = word_wrap; vbuf_needs_update = true; } if (color[0] != srcdata->color[0] || color[1] != srcdata->color[1]) { srcdata->color[0] = color[0]; srcdata->color[1] = color[1]; vbuf_needs_update = true; } bool from_file = obs_data_get_bool(settings, "from_file"); bool chat_log_mode = obs_data_get_bool(settings, "log_mode"); srcdata->log_mode = chat_log_mode; if (ft2_lib == NULL) goto error; if (srcdata->draw_effect == NULL) { char *effect_file = NULL; char *error_string = NULL; effect_file = obs_module_file("text_default.effect"); if (effect_file) { obs_enter_graphics(); srcdata->draw_effect = gs_effect_create_from_file( effect_file, &error_string); obs_leave_graphics(); bfree(effect_file); if (error_string != NULL) bfree(error_string); } } if (srcdata->font_size != font_size || srcdata->from_file != from_file) vbuf_needs_update = true; srcdata->file_load_failed = false; srcdata->from_file = from_file; if (srcdata->font_name != NULL) { if (strcmp(font_name, srcdata->font_name) == 0 && strcmp(font_style, srcdata->font_style) == 0 && font_flags == srcdata->font_flags && font_size == srcdata->font_size) goto skip_font_load; bfree(srcdata->font_name); bfree(srcdata->font_style); srcdata->font_name = NULL; srcdata->font_style = NULL; srcdata->max_h = 0; } srcdata->font_name = bstrdup(font_name); srcdata->font_style = bstrdup(font_style); srcdata->font_size = font_size; srcdata->font_flags = font_flags; if (!init_font(srcdata) || srcdata->font_face == NULL) { blog(LOG_WARNING, "FT2-text: Failed to load font %s", srcdata->font_name); goto error; } else { FT_Set_Pixel_Sizes(srcdata->font_face, 0, srcdata->font_size); FT_Select_Charmap(srcdata->font_face, FT_ENCODING_UNICODE); } if (srcdata->texbuf != NULL) { bfree(srcdata->texbuf); srcdata->texbuf = NULL; } srcdata->texbuf = bzalloc(texbuf_w * texbuf_h * 4); if (srcdata->font_face) cache_standard_glyphs(srcdata); skip_font_load:; if (from_file) { const char *tmp = obs_data_get_string(settings, "text_file"); if (!tmp || !*tmp) { blog(LOG_WARNING, "FT2-text: Failed to open %s for reading", tmp); goto error; } if (srcdata->text_file != NULL && strcmp(srcdata->text_file, tmp) == 0 && !vbuf_needs_update) goto error; bfree(srcdata->text_file); srcdata->text_file = bstrdup(tmp); if (chat_log_mode) read_from_end(srcdata, tmp); else load_text_from_file(srcdata, tmp); srcdata->last_checked = os_gettime_ns(); } else { const char *tmp = obs_data_get_string(settings, "text"); if (!tmp || !*tmp) goto error; if (srcdata->text != NULL) { bfree(srcdata->text); srcdata->text = NULL; } os_utf8_to_wcs_ptr(tmp, strlen(tmp), &srcdata->text); } if (srcdata->font_face) { cache_glyphs(srcdata, srcdata->text); set_up_vertex_buffer(srcdata); } error: obs_data_release(font_obj); }
static void update_params(struct obs_x264 *obsx264, obs_data_t *settings, char **params) { video_t *video = obs_encoder_video(obsx264->encoder); const struct video_output_info *voi = video_output_get_info(video); struct video_scale_info info; info.format = voi->format; info.colorspace = voi->colorspace; info.range = voi->range; obs_x264_video_info(obsx264, &info); int bitrate = (int)obs_data_get_int(settings, "bitrate"); int buffer_size = (int)obs_data_get_int(settings, "buffer_size"); int keyint_sec = (int)obs_data_get_int(settings, "keyint_sec"); int crf = (int)obs_data_get_int(settings, "crf"); int width = (int)obs_encoder_get_width(obsx264->encoder); int height = (int)obs_encoder_get_height(obsx264->encoder); bool use_bufsize = obs_data_get_bool(settings, "use_bufsize"); bool vfr = obs_data_get_bool(settings, "vfr"); bool cbr = obs_data_get_bool(settings, "cbr"); if (keyint_sec) obsx264->params.i_keyint_max = keyint_sec * voi->fps_num / voi->fps_den; if (!use_bufsize) buffer_size = bitrate; obsx264->params.b_vfr_input = vfr; obsx264->params.rc.i_vbv_max_bitrate = bitrate; obsx264->params.rc.i_vbv_buffer_size = buffer_size; obsx264->params.rc.i_bitrate = bitrate; obsx264->params.i_width = width; obsx264->params.i_height = height; obsx264->params.i_fps_num = voi->fps_num; obsx264->params.i_fps_den = voi->fps_den; obsx264->params.pf_log = log_x264; obsx264->params.p_log_private = obsx264; obsx264->params.i_log_level = X264_LOG_WARNING; obsx264->params.vui.i_transfer = get_x264_cs_val(info.colorspace, x264_transfer_names); obsx264->params.vui.i_colmatrix = get_x264_cs_val(info.colorspace, x264_colmatrix_names); obsx264->params.vui.i_colorprim = get_x264_cs_val(info.colorspace, x264_colorprim_names); obsx264->params.vui.b_fullrange = info.range == VIDEO_RANGE_FULL; /* use the new filler method for CBR to allow real-time adjusting of * the bitrate */ if (cbr) { obsx264->params.rc.f_rf_constant = 0.0f; obsx264->params.rc.i_rc_method = X264_RC_ABR; #if X264_BUILD >= 139 obsx264->params.rc.b_filler = true; #else obsx264->params.i_nal_hrd = X264_NAL_HRD_CBR; #endif } else { obsx264->params.rc.i_rc_method = X264_RC_CRF; obsx264->params.rc.f_rf_constant = (float)crf; } if (info.format == VIDEO_FORMAT_NV12) obsx264->params.i_csp = X264_CSP_NV12; else if (info.format == VIDEO_FORMAT_I420) obsx264->params.i_csp = X264_CSP_I420; else if (info.format == VIDEO_FORMAT_I444) obsx264->params.i_csp = X264_CSP_I444; else obsx264->params.i_csp = X264_CSP_NV12; while (*params) set_param(obsx264, *(params++)); info("settings:\n" "\tbitrate: %d\n" "\tbuffer size: %d\n" "\tcrf: %d%s\n" "\tfps_num: %d\n" "\tfps_den: %d\n" "\twidth: %d\n" "\theight: %d\n" "\tkeyint: %d\n" "\tvfr: %s\n" "\tcbr: %s", obsx264->params.rc.i_vbv_max_bitrate, obsx264->params.rc.i_vbv_buffer_size, (int)obsx264->params.rc.f_rf_constant, cbr ? " (0 when CBR is enabled)" : "", voi->fps_num, voi->fps_den, width, height, obsx264->params.i_keyint_max, vfr ? "on" : "off", cbr ? "on" : "off"); }
/** * Initialize the v4l2 device * * This function: * - tries to open the device * - sets pixelformat and requested resolution * - sets the requested framerate * - maps the buffers * - starts the capture thread */ static void v4l2_init(struct v4l2_data *data) { uint32_t input_caps; int fps_num, fps_denom; blog(LOG_INFO, "Start capture from %s", data->device_id); data->dev = v4l2_open(data->device_id, O_RDWR | O_NONBLOCK); if (data->dev == -1) { blog(LOG_ERROR, "Unable to open device"); goto fail; } /* set input */ if (v4l2_set_input(data->dev, &data->input) < 0) { blog(LOG_ERROR, "Unable to set input %d", data->input); goto fail; } blog(LOG_INFO, "Input: %d", data->input); if (v4l2_get_input_caps(data->dev, -1, &input_caps) < 0) { blog(LOG_ERROR, "Unable to get input capabilities"); goto fail; } /* set video standard if supported */ if (input_caps & V4L2_IN_CAP_STD) { if (v4l2_set_standard(data->dev, &data->standard) < 0) { blog(LOG_ERROR, "Unable to set video standard"); goto fail; } data->resolution = -1; data->framerate = -1; } /* set dv timing if supported */ #ifdef __FreeBSD__ if (input_caps & V4L2_IN_CAP_CUSTOM_TIMINGS) { #else if (input_caps & V4L2_IN_CAP_DV_TIMINGS) { #endif if (v4l2_set_dv_timing(data->dev, &data->dv_timing) < 0) { blog(LOG_ERROR, "Unable to set dv timing"); goto fail; } data->resolution = -1; data->framerate = -1; } /* set pixel format and resolution */ if (v4l2_set_format(data->dev, &data->resolution, &data->pixfmt, &data->linesize) < 0) { blog(LOG_ERROR, "Unable to set format"); goto fail; } if (v4l2_to_obs_video_format(data->pixfmt) == VIDEO_FORMAT_NONE) { blog(LOG_ERROR, "Selected video format not supported"); goto fail; } v4l2_unpack_tuple(&data->width, &data->height, data->resolution); blog(LOG_INFO, "Resolution: %dx%d", data->width, data->height); blog(LOG_INFO, "Pixelformat: %s", V4L2_FOURCC_STR(data->pixfmt)); blog(LOG_INFO, "Linesize: %d Bytes", data->linesize); /* set framerate */ if (v4l2_set_framerate(data->dev, &data->framerate) < 0) { blog(LOG_ERROR, "Unable to set framerate"); goto fail; } v4l2_unpack_tuple(&fps_num, &fps_denom, data->framerate); blog(LOG_INFO, "Framerate: %.2f fps", (float) fps_denom / fps_num); /* map buffers */ if (v4l2_create_mmap(data->dev, &data->buffers) < 0) { blog(LOG_ERROR, "Failed to map buffers"); goto fail; } /* start the capture thread */ if (os_event_init(&data->event, OS_EVENT_TYPE_MANUAL) != 0) goto fail; if (pthread_create(&data->thread, NULL, v4l2_thread, data) != 0) goto fail; return; fail: blog(LOG_ERROR, "Initialization failed"); v4l2_terminate(data); } /** Update source flags depending on the settings */ static void v4l2_update_source_flags(struct v4l2_data *data, obs_data_t *settings) { uint32_t flags = obs_source_get_flags(data->source); flags = (obs_data_get_bool(settings, "buffering")) ? flags & ~OBS_SOURCE_FLAG_UNBUFFERED : flags | OBS_SOURCE_FLAG_UNBUFFERED; obs_source_set_flags(data->source, flags); }