From 134faacd0105bffe3bd051d708f175010dd1e9b8 Mon Sep 17 00:00:00 2001 From: ronag Date: Thu, 25 Aug 2011 09:11:23 +0000 Subject: [PATCH] 2.0. ffmpeg_producer: Fixed integer overflow when looping. image_mixer: Refactored draw call parameters. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1282 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- core/mixer/image/image_kernel.cpp | 113 +++++++++----------- core/mixer/image/image_kernel.h | 15 ++- core/mixer/image/image_mixer.cpp | 74 ++++++++----- modules/ffmpeg/producer/ffmpeg_producer.cpp | 2 +- 4 files changed, 105 insertions(+), 99 deletions(-) diff --git a/core/mixer/image/image_kernel.cpp b/core/mixer/image/image_kernel.cpp index 3209bd4e9..e659c618b 100644 --- a/core/mixer/image/image_kernel.cpp +++ b/core/mixer/image/image_kernel.cpp @@ -61,23 +61,19 @@ struct image_kernel::implementation : boost::noncopyable std::shared_ptr shader_; bool blend_modes_; - void draw(ogl_device& ogl, - render_item&& item, - device_buffer& background, - const std::shared_ptr& local_key, - const std::shared_ptr& layer_key) + void draw(ogl_device& ogl, draw_params&& params) { static const double epsilon = 0.001; - CASPAR_ASSERT(item.pix_desc.planes.size() == item.textures.size()); + CASPAR_ASSERT(params.pix_desc.planes.size() == params.textures.size()); - if(item.textures.empty()) + if(params.textures.empty() || !params.background) return; - if(item.transform.opacity < epsilon) + if(params.transform.opacity < epsilon) return; - if(!std::all_of(item.textures.begin(), item.textures.end(), std::mem_fn(&device_buffer::ready))) + if(!std::all_of(params.textures.begin(), params.textures.end(), std::mem_fn(&device_buffer::ready))) { CASPAR_LOG(warning) << L"[image_mixer] Performance warning. Host to device transfer not complete, GPU will be stalled"; ogl.yield(); // Try to give it some more time. @@ -85,14 +81,14 @@ struct image_kernel::implementation : boost::noncopyable // Bind textures - for(size_t n = 0; n < item.textures.size(); ++n) - item.textures[n]->bind(n); + for(size_t n = 0; n < params.textures.size(); ++n) + params.textures[n]->bind(n); - if(local_key) - local_key->bind(texture_id::local_key); + if(params.local_key) + params.local_key->bind(texture_id::local_key); - if(layer_key) - layer_key->bind(texture_id::layer_key); + if(params.layer_key) + params.layer_key->bind(texture_id::layer_key); // Setup shader @@ -107,23 +103,23 @@ struct image_kernel::implementation : boost::noncopyable shader_->set("plane[3]", texture_id::plane3); shader_->set("local_key", texture_id::local_key); shader_->set("layer_key", texture_id::layer_key); - shader_->set("is_hd", item.pix_desc.planes.at(0).height > 700 ? 1 : 0); - shader_->set("has_local_key", local_key); - shader_->set("has_layer_key", layer_key); - shader_->set("pixel_format", item.pix_desc.pix_fmt); - shader_->set("opacity", item.transform.is_key ? 1.0 : item.transform.opacity); + shader_->set("is_hd", params.pix_desc.planes.at(0).height > 700 ? 1 : 0); + shader_->set("has_local_key", params.local_key); + shader_->set("has_layer_key", params.layer_key); + shader_->set("pixel_format", params.pix_desc.pix_fmt); + shader_->set("opacity", params.transform.is_key ? 1.0 : params.transform.opacity); // Setup blend_func - if(item.transform.is_key) - item.blend_mode = blend_mode::normal; + if(params.transform.is_key) + params.blend_mode = blend_mode::normal; if(blend_modes_) { - background.bind(6); + params.background->bind(6); shader_->set("background", texture_id::background); - shader_->set("blend_mode", item.blend_mode); + shader_->set("blend_mode", params.blend_mode); } else { @@ -132,74 +128,74 @@ struct image_kernel::implementation : boost::noncopyable // Setup image-adjustements - if(item.transform.levels.min_input > epsilon || - item.transform.levels.max_input < 1.0-epsilon || - item.transform.levels.min_output > epsilon || - item.transform.levels.max_output < 1.0-epsilon || - std::abs(item.transform.levels.gamma - 1.0) > epsilon) + if(params.transform.levels.min_input > epsilon || + params.transform.levels.max_input < 1.0-epsilon || + params.transform.levels.min_output > epsilon || + params.transform.levels.max_output < 1.0-epsilon || + std::abs(params.transform.levels.gamma - 1.0) > epsilon) { shader_->set("levels", true); - shader_->set("min_input", item.transform.levels.min_input); - shader_->set("max_input", item.transform.levels.max_input); - shader_->set("min_output", item.transform.levels.min_output); - shader_->set("max_output", item.transform.levels.max_output); - shader_->set("gamma", item.transform.levels.gamma); + shader_->set("min_input", params.transform.levels.min_input); + shader_->set("max_input", params.transform.levels.max_input); + shader_->set("min_output", params.transform.levels.min_output); + shader_->set("max_output", params.transform.levels.max_output); + shader_->set("gamma", params.transform.levels.gamma); } else shader_->set("levels", false); - if(std::abs(item.transform.brightness - 1.0) > epsilon || - std::abs(item.transform.saturation - 1.0) > epsilon || - std::abs(item.transform.contrast - 1.0) > epsilon) + if(std::abs(params.transform.brightness - 1.0) > epsilon || + std::abs(params.transform.saturation - 1.0) > epsilon || + std::abs(params.transform.contrast - 1.0) > epsilon) { shader_->set("csb", true); - shader_->set("brt", item.transform.brightness); - shader_->set("sat", item.transform.saturation); - shader_->set("con", item.transform.contrast); + shader_->set("brt", params.transform.brightness); + shader_->set("sat", params.transform.saturation); + shader_->set("con", params.transform.contrast); } else shader_->set("csb", false); // Setup interlacing - if(item.transform.field_mode == core::field_mode::progressive) + if(params.transform.field_mode == core::field_mode::progressive) ogl.disable(GL_POLYGON_STIPPLE); else { ogl.enable(GL_POLYGON_STIPPLE); - if(item.transform.field_mode == core::field_mode::upper) + if(params.transform.field_mode == core::field_mode::upper) ogl.stipple_pattern(upper_pattern); - else if(item.transform.field_mode == core::field_mode::lower) + else if(params.transform.field_mode == core::field_mode::lower) ogl.stipple_pattern(lower_pattern); } // Setup drawing area - ogl.viewport(0, 0, background.width(), background.height()); + ogl.viewport(0, 0, params.background->width(), params.background->height()); - auto m_p = item.transform.clip_translation; - auto m_s = item.transform.clip_scale; + auto m_p = params.transform.clip_translation; + auto m_s = params.transform.clip_scale; bool scissor = m_p[0] > std::numeric_limits::epsilon() || m_p[1] > std::numeric_limits::epsilon() || m_s[0] < (1.0 - std::numeric_limits::epsilon()) || m_s[1] < (1.0 - std::numeric_limits::epsilon()); if(scissor) { - double w = static_cast(background.width()); - double h = static_cast(background.height()); + double w = static_cast(params.background->width()); + double h = static_cast(params.background->height()); ogl.enable(GL_SCISSOR_TEST); ogl.scissor(static_cast(m_p[0]*w), static_cast(m_p[1]*h), static_cast(m_s[0]*w), static_cast(m_s[1]*h)); } - auto f_p = item.transform.fill_translation; - auto f_s = item.transform.fill_scale; + auto f_p = params.transform.fill_translation; + auto f_s = params.transform.fill_scale; // Set render target - ogl.attach(background); + ogl.attach(*params.background); // Draw @@ -214,7 +210,7 @@ struct image_kernel::implementation : boost::noncopyable ogl.disable(GL_SCISSOR_TEST); - item.textures.clear(); + params.textures.clear(); ogl.yield(); // Return resources to pool as early as possible. if(blend_modes_) @@ -227,18 +223,9 @@ struct image_kernel::implementation : boost::noncopyable }; image_kernel::image_kernel() : impl_(new implementation()){} -void image_kernel::draw(ogl_device& ogl, - render_item&& item, - device_buffer& background, - const std::shared_ptr& local_key, - const std::shared_ptr& layer_key) +void image_kernel::draw(ogl_device& ogl, draw_params&& params) { - impl_->draw(ogl, std::move(item), background, local_key, layer_key); -} - -bool operator==(const render_item& lhs, const render_item& rhs) -{ - return lhs.textures == rhs.textures && lhs.transform == rhs.transform; + impl_->draw(ogl, std::move(params)); } }} \ No newline at end of file diff --git a/core/mixer/image/image_kernel.h b/core/mixer/image/image_kernel.h index 2af0d5bcf..13827e734 100644 --- a/core/mixer/image/image_kernel.h +++ b/core/mixer/image/image_kernel.h @@ -33,27 +33,24 @@ namespace caspar { namespace core { class device_buffer; class ogl_device; -struct render_item +struct draw_params { pixel_format_desc pix_desc; std::vector> textures; frame_transform transform; blend_mode::type blend_mode; + std::shared_ptr background; + std::shared_ptr local_key; + std::shared_ptr layer_key; - render_item() : blend_mode(blend_mode::normal){} + draw_params() : blend_mode(blend_mode::normal){} }; -bool operator==(const render_item& lhs, const render_item& rhs); - class image_kernel : boost::noncopyable { public: image_kernel(); - void draw(ogl_device& ogl, - render_item&& item, - device_buffer& background, - const std::shared_ptr& local_key = nullptr, - const std::shared_ptr& layer_key = nullptr); + void draw(ogl_device& ogl, draw_params&& params); private: struct implementation; safe_ptr impl_; diff --git a/core/mixer/image/image_mixer.cpp b/core/mixer/image/image_mixer.cpp index ec167ce39..302d7af5e 100644 --- a/core/mixer/image/image_mixer.cpp +++ b/core/mixer/image/image_mixer.cpp @@ -48,10 +48,17 @@ using namespace boost::assign; namespace caspar { namespace core { +struct item +{ + pixel_format_desc pix_desc; + std::vector> textures; + frame_transform transform; +}; + struct layer { - std::vector items; - blend_mode::type blend_mode; + std::vector items; + blend_mode::type blend_mode; layer(blend_mode::type blend_mode) : blend_mode(blend_mode) { @@ -90,24 +97,24 @@ private: BOOST_FOREACH(auto& layer, upper) { - boost::remove_erase_if(layer.items, [](const render_item& item){return !(item.transform.field_mode & field_mode::upper);}); + boost::remove_erase_if(layer.items, [](const item& item){return !(item.transform.field_mode & field_mode::upper);}); BOOST_FOREACH(auto& item, layer.items) item.transform.field_mode = field_mode::upper; } BOOST_FOREACH(auto& layer, lower) { - boost::remove_erase_if(layer.items, [](const render_item& item){return !(item.transform.field_mode & field_mode::lower);}); + boost::remove_erase_if(layer.items, [](const item& item){return !(item.transform.field_mode & field_mode::lower);}); BOOST_FOREACH(auto& item, layer.items) item.transform.field_mode = field_mode::lower; } - draw(std::move(upper), *draw_buffer); - draw(std::move(lower), *draw_buffer); + draw(std::move(upper), draw_buffer); + draw(std::move(lower), draw_buffer); } else { - draw(std::move(layers), *draw_buffer); + draw(std::move(layers), draw_buffer); } auto host_buffer = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::read_only); @@ -121,8 +128,8 @@ private: return host_buffer; } - void draw(std::vector&& layers, - device_buffer& draw_buffer) + void draw(std::vector&& layers, + safe_ptr& draw_buffer) { std::shared_ptr layer_key_buffer; @@ -131,7 +138,7 @@ private: } void draw_layer(layer&& layer, - device_buffer& draw_buffer, + safe_ptr& draw_buffer, std::shared_ptr& layer_key_buffer) { if(layer.items.empty()) @@ -144,16 +151,17 @@ private: auto layer_draw_buffer = create_device_buffer(4); BOOST_FOREACH(auto& item, layer.items) - draw_item(std::move(item), *layer_draw_buffer, local_key_buffer, layer_key_buffer); + draw_item(std::move(item), layer_draw_buffer, local_key_buffer, layer_key_buffer); - render_item item; - item.pix_desc.pix_fmt = pixel_format::bgra; - item.pix_desc.planes = list_of(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); - item.textures = list_of(layer_draw_buffer); - item.transform = frame_transform(); - item.blend_mode = layer.blend_mode; - - kernel_.draw(channel_.ogl(), std::move(item), draw_buffer, nullptr, nullptr); + draw_params draw_params; + draw_params.pix_desc.pix_fmt = pixel_format::bgra; + draw_params.pix_desc.planes = list_of(pixel_format_desc::plane(channel_.get_format_desc().width, channel_.get_format_desc().height, 4)); + draw_params.textures = list_of(layer_draw_buffer); + draw_params.transform = frame_transform(); + draw_params.blend_mode = layer.blend_mode; + draw_params.background = draw_buffer; + + kernel_.draw(channel_.ogl(), std::move(draw_params)); } else // fast path { @@ -164,20 +172,34 @@ private: std::swap(local_key_buffer, layer_key_buffer); } - void draw_item(render_item&& item, - device_buffer& draw_buffer, + void draw_item(item&& item, + safe_ptr& draw_buffer, std::shared_ptr& local_key_buffer, std::shared_ptr& layer_key_buffer) - { + { + draw_params draw_params; + draw_params.pix_desc = std::move(item.pix_desc); + draw_params.textures = std::move(item.textures); + draw_params.transform = std::move(item.transform); + draw_params.blend_mode = blend_mode::normal; + if(item.transform.is_key) { local_key_buffer = local_key_buffer ? local_key_buffer : create_device_buffer(1); - kernel_.draw(channel_.ogl(), std::move(item), *local_key_buffer, nullptr, nullptr); + + draw_params.background = local_key_buffer; + draw_params.local_key = nullptr; + draw_params.layer_key = nullptr; + + kernel_.draw(channel_.ogl(), std::move(draw_params)); } else { - kernel_.draw(channel_.ogl(), std::move(item), draw_buffer, local_key_buffer, layer_key_buffer); - local_key_buffer = nullptr; + draw_params.background = draw_buffer; + draw_params.local_key = std::move(local_key_buffer); + draw_params.layer_key = layer_key_buffer; + + kernel_.draw(channel_.ogl(), std::move(draw_params)); } } @@ -218,7 +240,7 @@ public: if(frame.get_frame_transform().field_mode == field_mode::empty) return; - core::render_item item; + item item; item.pix_desc = frame.get_pixel_format_desc(); item.textures = frame.get_textures(); item.transform = transform_stack_.back(); diff --git a/modules/ffmpeg/producer/ffmpeg_producer.cpp b/modules/ffmpeg/producer/ffmpeg_producer.cpp index 3db902f5f..839e35a1d 100644 --- a/modules/ffmpeg/producer/ffmpeg_producer.cpp +++ b/modules/ffmpeg/producer/ffmpeg_producer.cpp @@ -172,7 +172,7 @@ public: virtual int64_t nb_frames() const { if(loop_) - return std::numeric_limits::max(); + return std::numeric_limits::max(); // This function estimates nb_frames until input has read all packets for one loop, at which point the count should be accurate. -- 2.39.2