diff --git a/.gitignore b/.gitignore index c40a864eb..5d4e8199b 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,8 @@ ltmain.sh .depend tags *.trace +*.vsp +*.psess *.swp *.dat *.clbin diff --git a/build/data/libobs/format_conversion.effect b/build/data/libobs/format_conversion.effect new file mode 100644 index 000000000..ddb4ac31f --- /dev/null +++ b/build/data/libobs/format_conversion.effect @@ -0,0 +1,136 @@ +/****************************************************************************** + Copyright (C) 2014 by Hugh Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +//#define DEBUGGING + +uniform float4x4 ViewProj; + +uniform float u_plane_offset; +uniform float v_plane_offset; + +uniform float width; +uniform float height; +uniform float width_i; +uniform float height_i; +uniform float width_d2; +uniform float height_d2; +uniform float width_d2_i; +uniform float height_d2_i; +uniform float input_width; +uniform float input_height; + +uniform texture2d image; + +sampler_state def_sampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct VertInOut { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertInOut VSDefault(VertInOut vert_in) +{ + VertInOut vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = vert_in.uv; + return vert_out; +} + +float4 PSPlanar420(VertInOut vert_in) : TARGET +{ +#ifdef _OPENGL + float v_mul = floor((1.0 - vert_in.uv.y) * input_height); +#else + float v_mul = floor(vert_in.uv.y * input_height); +#endif + + float byte_offset = floor((v_mul + vert_in.uv.x) * input_width) * 4.0; + + float2 sample_pos[4]; + + if (byte_offset < u_plane_offset) { +#ifdef DEBUGGING + return float4(1.0f, 1.0f, 1.0f, 1.0f); +#endif + + float lum_u = fmod(byte_offset, width) * width_i; + float lum_v = floor(byte_offset * width_i) * height_i; + + /* move to texel centers to sample the 4 pixels properly */ + lum_u += width_i * 0.5; + lum_v += height_i * 0.5; + + sample_pos[0] = float2(lum_u, lum_v); + sample_pos[1] = float2(lum_u += width_i, lum_v); + sample_pos[2] = float2(lum_u += width_i, lum_v); + sample_pos[3] = float2(lum_u + width_i, lum_v); + + } else { +#ifdef DEBUGGING + return ((byte_offset < v_plane_offset) ? + float4(0.5f, 0.5f, 0.5f, 0.5f) : + float4(0.2f, 0.2f, 0.2f, 0.2f)); +#endif + + float new_offset = byte_offset - + ((byte_offset < v_plane_offset) ? + u_plane_offset : v_plane_offset); + + float ch_u = fmod(new_offset, width_d2) * width_d2_i; + float ch_v = floor(new_offset * width_d2_i) * height_d2_i; + float width_i2 = width_i*2.0; + + /* move to the borders of each set of 4 pixels to force it + * to do bilinear averaging */ + ch_u += width_i; + ch_v += height_i; + + sample_pos[0] = float2(ch_u, ch_v); + sample_pos[1] = float2(ch_u += width_i2, ch_v); + sample_pos[2] = float2(ch_u += width_i2, ch_v); + sample_pos[3] = float2(ch_u + width_i2, ch_v); + } + + float4x4 out_val = { + image.Sample(def_sampler, sample_pos[0]), + image.Sample(def_sampler, sample_pos[1]), + image.Sample(def_sampler, sample_pos[2]), + image.Sample(def_sampler, sample_pos[3]) + }; + + out_val = transpose(out_val); + + if (byte_offset < u_plane_offset) + return out_val[1]; + else if (byte_offset < v_plane_offset) + return out_val[0]; + else + return out_val[2]; +} + +technique Planar420 +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSPlanar420(vert_in); + } +} diff --git a/libobs-d3d11/d3d11-exports.h b/libobs-d3d11/d3d11-exports.h index 7a6d8eb6c..750b29ad0 100644 --- a/libobs-d3d11/d3d11-exports.h +++ b/libobs-d3d11/d3d11-exports.h @@ -21,6 +21,7 @@ extern "C" { +EXPORT const char *device_preprocessor_name(void); EXPORT device_t device_create(struct gs_init_data *data); EXPORT void device_destroy(device_t device); EXPORT void device_entercontext(device_t device); diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index dceb0484f..cd3ac219c 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -421,6 +421,11 @@ gs_device::gs_device(gs_init_data *data) device_setrendertarget(this, NULL, NULL); } +const char *device_preprocessor_name(void) +{ + return "_D3D11"; +} + gs_device *device_create(gs_init_data *data) { gs_device *device = NULL; diff --git a/libobs-opengl/gl-exports.h b/libobs-opengl/gl-exports.h index 318def223..06070bcc3 100644 --- a/libobs-opengl/gl-exports.h +++ b/libobs-opengl/gl-exports.h @@ -19,6 +19,7 @@ #include +EXPORT const char *device_preprocessor_name(void); EXPORT device_t device_create(struct gs_init_data *data); EXPORT void device_destroy(device_t device); EXPORT void device_entercontext(device_t device); diff --git a/libobs-opengl/gl-helpers.c b/libobs-opengl/gl-helpers.c index b2325f074..c90a00d59 100644 --- a/libobs-opengl/gl-helpers.c +++ b/libobs-opengl/gl-helpers.c @@ -155,8 +155,12 @@ bool update_buffer(GLenum target, GLuint buffer, void *data, size_t size) if (!gl_bind_buffer(target, buffer)) return false; - ptr = glMapBuffer(target, GL_WRITE_ONLY); - success = gl_success("glMapBuffer"); + /* glMapBufferRange with these flags will actually give far better + * performance than a plain glMapBuffer call */ + ptr = glMapBufferRange(target, 0, size, + GL_MAP_WRITE_BIT | + GL_MAP_INVALIDATE_BUFFER_BIT); + success = gl_success("glMapBufferRange"); if (success && ptr) { memcpy(ptr, data, size); glUnmapBuffer(target); diff --git a/libobs-opengl/gl-shaderparser.c b/libobs-opengl/gl-shaderparser.c index e1f8c0d4b..fe953a622 100644 --- a/libobs-opengl/gl-shaderparser.c +++ b/libobs-opengl/gl-shaderparser.c @@ -239,7 +239,7 @@ static inline void gl_write_structs(struct gl_shader_parser *glsp) * clip -> (unsupported) * ddx -> dFdx * ddy -> dFdy - * fmod -> (unsupported) + * fmod -> mod (XXX: these are different if sign is negative) * frac -> fract * lerp -> mix * lit -> (unsupported) @@ -367,6 +367,8 @@ static bool gl_write_intrinsic(struct gl_shader_parser *glsp, dstr_cat(&glsp->gl_string, "fract"); } else if (strref_cmp(&token->str, "lerp") == 0) { dstr_cat(&glsp->gl_string, "mix"); + } else if (strref_cmp(&token->str, "fmod") == 0) { + dstr_cat(&glsp->gl_string, "mod"); } else if (strref_cmp(&token->str, "rsqrt") == 0) { dstr_cat(&glsp->gl_string, "inversesqrt"); } else if (strref_cmp(&token->str, "saturate") == 0) { diff --git a/libobs-opengl/gl-subsystem.c b/libobs-opengl/gl-subsystem.c index 7a27370c2..077e2bcda 100644 --- a/libobs-opengl/gl-subsystem.c +++ b/libobs-opengl/gl-subsystem.c @@ -163,6 +163,11 @@ void convert_sampler_info(struct gs_sampler_state *sampler, info->max_anisotropy, sampler->max_anisotropy); } +const char *device_preprocessor_name(void) +{ + return "_OPENGL"; +} + device_t device_create(struct gs_init_data *info) { struct gs_device *device = bzalloc(sizeof(struct gs_device)); diff --git a/libobs-opengl/gl-vertexbuffer.c b/libobs-opengl/gl-vertexbuffer.c index f9c1093e1..08b34ad55 100644 --- a/libobs-opengl/gl-vertexbuffer.c +++ b/libobs-opengl/gl-vertexbuffer.c @@ -20,7 +20,7 @@ static bool create_buffers(struct gs_vertex_buffer *vb) { - GLenum usage = vb->dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + GLenum usage = vb->dynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW; size_t i; if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->vertex_buffer, diff --git a/libobs/graphics/effect-parser.c b/libobs/graphics/effect-parser.c index f9164502f..a9d9d6af7 100644 --- a/libobs/graphics/effect-parser.c +++ b/libobs/graphics/effect-parser.c @@ -914,11 +914,26 @@ error: static bool ep_compile(struct effect_parser *ep); +extern const char *gs_preprocessor_name(void); + bool ep_parse(struct effect_parser *ep, effect_t effect, const char *effect_string, const char *file) { bool success; + const char *graphics_preprocessor = gs_preprocessor_name(); + + if (graphics_preprocessor) { + struct cf_def def; + + cf_def_init(&def); + def.name.str.array = graphics_preprocessor; + def.name.str.len = strlen(graphics_preprocessor); + + strref_copy(&def.name.unmerged_str, &def.name.str); + cf_preprocessor_add_def(&ep->cfp.pp, &def); + } + ep->effect = effect; if (!cf_parser_parse(&ep->cfp, effect_string, file)) return false; diff --git a/libobs/graphics/graphics-imports.c b/libobs/graphics/graphics-imports.c index 8b1da5f21..192d96fd2 100644 --- a/libobs/graphics/graphics-imports.c +++ b/libobs/graphics/graphics-imports.c @@ -40,6 +40,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, { bool success = true; + GRAPHICS_IMPORT(device_preprocessor_name); GRAPHICS_IMPORT(device_create); GRAPHICS_IMPORT(device_destroy); GRAPHICS_IMPORT(device_entercontext); diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h index e32052809..3f3f1605e 100644 --- a/libobs/graphics/graphics-internal.h +++ b/libobs/graphics/graphics-internal.h @@ -24,6 +24,7 @@ #include "matrix4.h" struct gs_exports { + const char *(*device_preprocessor_name)(void); device_t (*device_create)(struct gs_init_data *data); void (*device_destroy)(device_t device); void (*device_entercontext)(device_t device); diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c index c82d6da44..f94ee33ac 100644 --- a/libobs/graphics/graphics.c +++ b/libobs/graphics/graphics.c @@ -865,6 +865,12 @@ void gs_perspective(float angle, float aspect, float near, float far) /* ------------------------------------------------------------------------- */ +const char *gs_preprocessor_name(void) +{ + graphics_t graphics = thread_graphics; + return graphics->exports.device_preprocessor_name(); +} + swapchain_t gs_create_swapchain(struct gs_init_data *data) { graphics_t graphics = thread_graphics; diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index f82df5092..87a6eba43 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -87,11 +87,14 @@ struct obs_core_video { stagesurf_t copy_surfaces[NUM_TEXTURES]; texture_t render_textures[NUM_TEXTURES]; texture_t output_textures[NUM_TEXTURES]; + texture_t convert_textures[NUM_TEXTURES]; bool textures_rendered[NUM_TEXTURES]; bool textures_output[NUM_TEXTURES]; bool textures_copied[NUM_TEXTURES]; + bool textures_converted[NUM_TEXTURES]; struct source_frame convert_frames[NUM_TEXTURES]; effect_t default_effect; + effect_t conversion_effect; stagesurf_t mapped_surface; int cur_texture; @@ -99,6 +102,15 @@ struct obs_core_video { pthread_t video_thread; bool thread_initialized; + bool gpu_conversion; + const char *conversion_tech; + uint32_t conversion_height; + uint32_t plane_offsets[3]; + uint32_t plane_sizes[3]; + uint32_t plane_linewidth[3]; + + uint32_t output_width; + uint32_t output_height; uint32_t base_width; uint32_t base_height; diff --git a/libobs/obs-video.c b/libobs/obs-video.c index 7acfc2f96..f89ebe30f 100644 --- a/libobs/obs-video.c +++ b/libobs/obs-video.c @@ -64,6 +64,7 @@ static inline void render_displays(void) static inline void set_render_size(uint32_t width, uint32_t height) { gs_enable_depthtest(false); + gs_enable_blending(false); gs_setcullmode(GS_NEITHER); gs_ortho(0.0f, (float)width, 0.0f, (float)height, -100.0f, 100.0f); @@ -137,15 +138,77 @@ static inline void render_output_texture(struct obs_core_video *video, video->textures_output[cur_texture] = true; } -static inline void stage_output_texture(struct obs_core_video *video, +static inline void set_eparam(effect_t effect, const char *name, float val) +{ + eparam_t param = effect_getparambyname(effect, name); + effect_setfloat(effect, param, val); +} + +static void render_convert_texture(struct obs_core_video *video, int cur_texture, int prev_texture) { texture_t texture = video->output_textures[prev_texture]; - stagesurf_t copy = video->copy_surfaces[cur_texture]; + texture_t target = video->convert_textures[cur_texture]; + float fwidth = (float)video->output_width; + float fheight = (float)video->output_height; + size_t passes, i; + + effect_t effect = video->conversion_effect; + eparam_t image = effect_getparambyname(effect, "image"); + technique_t tech = effect_gettechnique(effect, + video->conversion_tech); + + if (!video->textures_output[prev_texture]) + return; + + set_eparam(effect, "u_plane_offset", (float)video->plane_offsets[1]); + set_eparam(effect, "v_plane_offset", (float)video->plane_offsets[2]); + set_eparam(effect, "width", fwidth); + set_eparam(effect, "height", fheight); + set_eparam(effect, "width_i", 1.0f / fwidth); + set_eparam(effect, "height_i", 1.0f / fheight); + set_eparam(effect, "width_d2", fwidth * 0.5f); + set_eparam(effect, "height_d2", fheight * 0.5f); + set_eparam(effect, "width_d2_i", 1.0f / (fwidth * 0.5f)); + set_eparam(effect, "height_d2_i", 1.0f / (fheight * 0.5f)); + set_eparam(effect, "input_width", fwidth); + set_eparam(effect, "input_height", (float)video->conversion_height); + + effect_settexture(effect, image, texture); + + gs_setrendertarget(target, NULL); + set_render_size(video->output_width, video->conversion_height); + + passes = technique_begin(tech); + for (i = 0; i < passes; i++) { + technique_beginpass(tech, i); + gs_draw_sprite(texture, 0, video->output_width, + video->conversion_height); + technique_endpass(tech); + } + technique_end(tech); + + video->textures_converted[cur_texture] = true; +} + +static inline void stage_output_texture(struct obs_core_video *video, + int cur_texture, int prev_texture) +{ + texture_t texture; + bool texture_ready; + stagesurf_t copy = video->copy_surfaces[cur_texture]; + + if (video->gpu_conversion) { + texture = video->convert_textures[prev_texture]; + texture_ready = video->textures_converted[prev_texture]; + } else { + texture = video->output_textures[prev_texture]; + texture_ready = video->output_textures[prev_texture]; + } unmap_last_surface(video); - if (!video->textures_output[prev_texture]) + if (!texture_ready) return; gs_stage_texture(copy, texture); @@ -163,9 +226,13 @@ static inline void render_video(struct obs_core_video *video, int cur_texture, render_main_texture(video, cur_texture); render_output_texture(video, cur_texture, prev_texture); + if (video->gpu_conversion) + render_convert_texture(video, cur_texture, prev_texture); + stage_output_texture(video, cur_texture, prev_texture); gs_setrendertarget(NULL, NULL); + gs_enable_blending(true); gs_endscene(); } @@ -186,6 +253,90 @@ static inline bool download_frame(struct obs_core_video *video, return true; } +static inline uint32_t calc_linesize(uint32_t pos, uint32_t linesize) +{ + uint32_t size = pos % linesize; + return size ? size : linesize; +} + +static void copy_dealign( + uint8_t *dst, uint32_t dst_pos, uint32_t dst_linesize, + const uint8_t *src, uint32_t src_pos, uint32_t src_linesize, + uint32_t remaining) +{ + while (remaining) { + uint32_t src_remainder = src_pos % src_linesize; + uint32_t dst_offset = dst_linesize - src_remainder; + uint32_t src_offset = src_linesize - src_remainder; + + if (remaining < dst_offset) { + memcpy(dst + dst_pos, src + src_pos, remaining); + src_pos += remaining; + dst_pos += remaining; + remaining = 0; + } else { + memcpy(dst + dst_pos, src + src_pos, dst_offset); + src_pos += src_offset; + dst_pos += dst_offset; + remaining -= dst_offset; + } + } +} + +static inline uint32_t make_aligned_linesize_offset(uint32_t offset, + uint32_t dst_linesize, uint32_t src_linesize) +{ + uint32_t remainder = offset % dst_linesize; + return (offset / dst_linesize) * src_linesize + remainder; +} + +static void fix_gpu_converted_alignment(struct obs_core_video *video, + struct video_frame *frame, int cur_texture) +{ + struct source_frame *new_frame = &video->convert_frames[cur_texture]; + uint32_t src_linesize = frame->linesize[0]; + uint32_t dst_linesize = video->output_width * 4; + uint32_t src_pos = 0; + + for (size_t i = 0; i < 3; i++) { + if (video->plane_linewidth[i] == 0) + break; + + src_pos = make_aligned_linesize_offset(video->plane_offsets[i], + dst_linesize, src_linesize); + + copy_dealign(new_frame->data[i], 0, dst_linesize, + frame->data[0], src_pos, src_linesize, + video->plane_sizes[i]); + } + + /* replace with cached frames */ + for (size_t i = 0; i < MAX_AV_PLANES; i++) { + frame->data[i] = new_frame->data[i]; + frame->linesize[i] = new_frame->linesize[i]; + } +} + +static bool set_gpu_converted_data(struct obs_core_video *video, + struct video_frame *frame, int cur_texture) +{ + if (frame->linesize[0] == video->output_width*4) { + for (size_t i = 0; i < 3; i++) { + if (video->plane_linewidth[i] == 0) + break; + + frame->linesize[i] = video->plane_linewidth[i]; + frame->data[i] = + frame->data[0] + video->plane_offsets[i]; + } + + } else { + fix_gpu_converted_alignment(video, frame, cur_texture); + } + + return true; +} + static bool convert_frame(struct obs_core_video *video, struct video_frame *frame, const struct video_output_info *info, int cur_texture) @@ -223,9 +374,14 @@ static inline void output_video_data(struct obs_core_video *video, const struct video_output_info *info; info = video_output_getinfo(video->video); - if (format_is_yuv(info->format)) + if (video->gpu_conversion) { + if (!set_gpu_converted_data(video, frame, cur_texture)) + return; + + } else if (format_is_yuv(info->format)) { if (!convert_frame(video, frame, info, cur_texture)) return; + } video_output_frame(video->video, frame); } diff --git a/libobs/obs.c b/libobs/obs.c index cfea0b47c..4a2dcf497 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -47,16 +47,92 @@ static inline void make_video_info(struct video_output_info *vi, vi->height = ovi->output_height; } +#define PIXEL_SIZE 4 + +#define GET_ALIGN(val, align) \ + (((val) + (align-1)) & ~(align-1)) + +static inline void set_420p_sizes(const struct obs_video_info *ovi) +{ + struct obs_core_video *video = &obs->video; + uint32_t chroma_pixels; + uint32_t total_bytes; + + chroma_pixels = (ovi->output_width * ovi->output_height / 4); + chroma_pixels = GET_ALIGN(chroma_pixels, PIXEL_SIZE); + + video->plane_offsets[0] = 0; + video->plane_offsets[1] = ovi->output_width * ovi->output_height; + video->plane_offsets[2] = video->plane_offsets[1] + chroma_pixels; + + video->plane_linewidth[0] = ovi->output_width; + video->plane_linewidth[1] = ovi->output_width/2; + video->plane_linewidth[2] = ovi->output_width/2; + + video->plane_sizes[0] = video->plane_offsets[1]; + video->plane_sizes[1] = video->plane_sizes[0]/4; + video->plane_sizes[2] = video->plane_sizes[1]; + + total_bytes = video->plane_offsets[2] + chroma_pixels; + + video->conversion_height = + (total_bytes/PIXEL_SIZE + ovi->output_width-1) / + ovi->output_width; + + video->conversion_height = GET_ALIGN(video->conversion_height, 2); + video->conversion_tech = "Planar420"; +} + +static inline void calc_gpu_conversion_sizes(const struct obs_video_info *ovi) +{ + obs->video.conversion_height = 0; + memset(obs->video.plane_offsets, 0, sizeof(obs->video.plane_offsets)); + memset(obs->video.plane_sizes, 0, sizeof(obs->video.plane_sizes)); + memset(obs->video.plane_linewidth, 0, + sizeof(obs->video.plane_linewidth)); + + switch ((uint32_t)ovi->output_format) { + case VIDEO_FORMAT_I420: + set_420p_sizes(ovi); + } +} + +static bool obs_init_gpu_conversion(struct obs_video_info *ovi) +{ + struct obs_core_video *video = &obs->video; + + calc_gpu_conversion_sizes(ovi); + + if (!video->conversion_height) { + blog(LOG_INFO, "GPU conversion not available for format: %u", + (unsigned int)ovi->output_format); + video->gpu_conversion = false; + return true; + } + + for (size_t i = 0; i < NUM_TEXTURES; i++) { + video->convert_textures[i] = gs_create_texture( + ovi->output_width, video->conversion_height, + GS_RGBA, 1, NULL, GS_RENDERTARGET); + + if (!video->convert_textures[i]) + return false; + } + + return true; +} + static bool obs_init_textures(struct obs_video_info *ovi) { struct obs_core_video *video = &obs->video; bool yuv = format_is_yuv(ovi->output_format); + uint32_t output_height = video->gpu_conversion ? + video->conversion_height : ovi->output_height; size_t i; for (i = 0; i < NUM_TEXTURES; i++) { video->copy_surfaces[i] = gs_create_stagesurface( - ovi->output_width, ovi->output_height, - GS_RGBA); + ovi->output_width, output_height, GS_RGBA); if (!video->copy_surfaces[i]) return false; @@ -92,8 +168,12 @@ static bool obs_init_graphics(struct obs_video_info *ovi) int errorcode; make_gs_init_data(&graphics_data, ovi); - video->base_width = ovi->base_width; - video->base_height = ovi->base_height; + video->base_width = ovi->base_width; + video->base_height = ovi->base_height; + video->output_width = ovi->output_width; + video->output_height = ovi->output_height; + + video->gpu_conversion = ovi->gpu_conversion; errorcode = gs_create(&video->graphics, ovi->graphics_module, &graphics_data); @@ -106,7 +186,9 @@ static bool obs_init_graphics(struct obs_video_info *ovi) gs_entercontext(video->graphics); - if (!obs_init_textures(ovi)) + if (ovi->gpu_conversion && !obs_init_gpu_conversion(ovi)) + success = false; + if (success && !obs_init_textures(ovi)) success = false; if (success) { @@ -114,8 +196,16 @@ static bool obs_init_graphics(struct obs_video_info *ovi) video->default_effect = gs_create_effect_from_file(filename, NULL); bfree(filename); + + filename = find_libobs_data_file("format_conversion.effect"); + video->conversion_effect = gs_create_effect_from_file(filename, + NULL); + bfree(filename); + if (!video->default_effect) success = false; + if (!video->conversion_effect) + success = false; } gs_leavecontext(); @@ -195,15 +285,18 @@ static void obs_free_graphics(void) for (i = 0; i < NUM_TEXTURES; i++) { stagesurface_destroy(video->copy_surfaces[i]); texture_destroy(video->render_textures[i]); + texture_destroy(video->convert_textures[i]); texture_destroy(video->output_textures[i]); source_frame_free(&video->convert_frames[i]); - video->copy_surfaces[i] = NULL; - video->render_textures[i] = NULL; - video->output_textures[i] = NULL; + video->copy_surfaces[i] = NULL; + video->render_textures[i] = NULL; + video->convert_textures[i] = NULL; + video->output_textures[i] = NULL; } effect_destroy(video->default_effect); + effect_destroy(video->conversion_effect); video->default_effect = NULL; gs_leavecontext(); diff --git a/libobs/obs.h b/libobs/obs.h index 211a19729..32d3c56ca 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -118,6 +118,9 @@ struct obs_video_info { uint32_t adapter; struct gs_window window; /**< Window to render to */ + + /** Use shaders to convert to different color formats */ + bool gpu_conversion; }; /** diff --git a/libobs/util/cf-lexer.c b/libobs/util/cf-lexer.c index 88a43547c..832880d5c 100644 --- a/libobs/util/cf-lexer.c +++ b/libobs/util/cf-lexer.c @@ -1295,7 +1295,7 @@ void cf_preprocessor_add_def(struct cf_preprocessor *pp, struct cf_def *def) cf_def_free(existing); memcpy(existing, def, sizeof(struct cf_def)); } else { - da_push_back(pp->defines, &def); + da_push_back(pp->defines, def); } } diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp index 4f030a117..277f0b045 100644 --- a/obs/window-basic-main.cpp +++ b/obs/window-basic-main.cpp @@ -282,16 +282,17 @@ bool OBSBasic::InitGraphics() App()->GetConfigFPS(ovi.fps_num, ovi.fps_den); ovi.graphics_module = App()->GetRenderModule(); - ovi.base_width = (uint32_t)config_get_uint(GetGlobalConfig(), + ovi.base_width = (uint32_t)config_get_uint(GetGlobalConfig(), "Video", "BaseCX"); - ovi.base_height = (uint32_t)config_get_uint(GetGlobalConfig(), + ovi.base_height = (uint32_t)config_get_uint(GetGlobalConfig(), "Video", "BaseCY"); - ovi.output_width = (uint32_t)config_get_uint(GetGlobalConfig(), + ovi.output_width = (uint32_t)config_get_uint(GetGlobalConfig(), "Video", "OutputCX"); - ovi.output_height = (uint32_t)config_get_uint(GetGlobalConfig(), + ovi.output_height = (uint32_t)config_get_uint(GetGlobalConfig(), "Video", "OutputCY"); - ovi.output_format = VIDEO_FORMAT_I420; - ovi.adapter = 0; + ovi.output_format = VIDEO_FORMAT_I420; + ovi.adapter = 0; + ovi.gpu_conversion = true; QTToGSWindow(ui->preview, ovi.window); diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-output.c b/plugins/obs-ffmpeg/obs-ffmpeg-output.c index 650dc4308..8ad83a7b4 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-output.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-output.c @@ -20,7 +20,6 @@ #include #include -#include struct ffmpeg_data { AVStream *video; diff --git a/vs/2013/OBS.sln b/vs/2013/OBS.sln index e9d5e54f8..23e7f91f4 100644 --- a/vs/2013/OBS.sln +++ b/vs/2013/OBS.sln @@ -39,6 +39,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obs-ffmpeg", "obs-ffmpeg\ob EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obs-studio", "obs-studio\obs-studio.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6AE25DF7-A903-48AD-8DA4-9902010AEB11}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -102,6 +104,7 @@ Global {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.ActiveCfg = Release|Win32 {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.Build.0 = Release|Win32 {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|x64.ActiveCfg = Release|Win32 + {76226D20-1972-4789-A595-EDACC7A76DC3}.Release|x64.Build.0 = Release|Win32 {36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|Win32.ActiveCfg = Debug|Win32 {36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|Win32.Build.0 = Debug|Win32 {36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|x64.ActiveCfg = Debug|x64