\r
#include "image_kernel.h"\r
\r
-#include "../util/write_frame.h"\r
+#include "../util/data_frame.h"\r
#include "../util/context.h"\r
#include "../util/host_buffer.h"\r
#include "../util/device_buffer.h"\r
#include <common/concurrency/async.h>\r
#include <common/memory/memcpy.h>\r
\r
-#include <core/frame/write_frame.h>\r
+#include <core/frame/data_frame.h>\r
#include <core/frame/frame_transform.h>\r
#include <core/frame/pixel_format.h>\r
#include <core/video_format.h>\r
struct item\r
{\r
core::pixel_format_desc pix_desc;\r
+ core::field_mode field_mode;\r
std::vector<spl::shared_ptr<host_buffer>> buffers;\r
std::vector<future_texture> textures;\r
- core::frame_transform transform;\r
-\r
+ core::image_transform transform;\r
\r
item()\r
: pix_desc(core::pixel_format::invalid)\r
+ , field_mode(core::field_mode::empty)\r
{\r
}\r
};\r
{\r
spl::shared_ptr<context> ogl_;\r
image_kernel kernel_;\r
- std::pair<std::vector<layer>, boost::shared_future<boost::iterator_range<const uint8_t*>>> last_image_;\r
+ std::pair<std::vector<layer>, boost::shared_future<boost::iterator_range<const uint8_t*>>> last_image_; \r
public:\r
image_renderer(const spl::shared_ptr<context>& ogl)\r
: ogl_(ogl)\r
, kernel_(ogl_)\r
{\r
- CASPAR_LOG(info) << L"Initialized OpenGL GPU Accelerated Image Mixer";\r
}\r
\r
boost::shared_future<boost::iterator_range<const uint8_t*>> operator()(std::vector<layer> layers, const core::video_format_desc& format_desc)\r
(kernel_.has_blend_modes() && layers.at(0).blend_mode != core::blend_mode::normal) == false &&\r
layers.at(0).items.at(0).pix_desc.format == core::pixel_format::bgra &&\r
layers.at(0).items.at(0).buffers.at(0)->size() == format_desc.size &&\r
- layers.at(0).items.at(0).transform == core::frame_transform())\r
+ layers.at(0).items.at(0).transform == core::image_transform())\r
{ // Bypass GPU using streaming loads to cachable memory.\r
auto uswc_buffer = layers.at(0).items.at(0).buffers.at(0);\r
auto buffer = std::make_shared<std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>>>(uswc_buffer->size());\r
const core::video_format_desc& format_desc)\r
{ \r
// Remove empty items.\r
- boost::range::remove_erase_if(layer.items, [](const item& item)\r
+ boost::range::remove_erase_if(layer.items, [&](const item& item)\r
{\r
return item.transform.field_mode == core::field_mode::empty;\r
});\r
+ \r
+ // Remove first field stills.\r
+ boost::range::remove_erase_if(layer.items, [&](const item& item)\r
+ {\r
+ return item.transform.is_still && item.transform.field_mode == format_desc.field_mode; // only us last field for stills.\r
+ });\r
\r
if(layer.items.empty())\r
return;\r
std::shared_ptr<device_buffer>& local_key_buffer, \r
std::shared_ptr<device_buffer>& local_mix_buffer,\r
const core::video_format_desc& format_desc)\r
- { \r
+ { \r
+ if(item.pix_desc.planes.at(0).height == 480) // NTSC DV\r
+ {\r
+ item.transform.fill_translation[1] += 2.0/static_cast<double>(format_desc.height);\r
+ item.transform.fill_scale[1] = 1.0 - 6.0*1.0/static_cast<double>(format_desc.height);\r
+ }\r
+ \r
+ // Fix field-order if needed\r
+ if(item.field_mode == core::field_mode::lower && format_desc.field_mode == core::field_mode::upper)\r
+ item.transform.fill_translation[1] += 1.0/static_cast<double>(format_desc.height);\r
+ else if(item.field_mode == core::field_mode::upper && format_desc.field_mode == core::field_mode::lower)\r
+ item.transform.fill_translation[1] -= 1.0/static_cast<double>(format_desc.height);\r
+ \r
draw_params draw_params;\r
draw_params.pix_desc = std::move(item.pix_desc);\r
draw_params.transform = std::move(item.transform);\r
draw_params.pix_desc.format = core::pixel_format::bgra;\r
draw_params.pix_desc.planes = list_of(core::pixel_format_desc::plane(source_buffer->width(), source_buffer->height(), 4));\r
draw_params.textures = list_of(source_buffer);\r
- draw_params.transform = core::frame_transform();\r
+ draw_params.transform = core::image_transform();\r
draw_params.blend_mode = blend_mode;\r
draw_params.background = draw_buffer;\r
\r
{ \r
spl::shared_ptr<context> ogl_;\r
image_renderer renderer_;\r
- std::vector<core::frame_transform> transform_stack_;\r
+ std::vector<core::image_transform> transform_stack_;\r
std::vector<layer> layers_; // layer/stream/items\r
public:\r
impl(const spl::shared_ptr<context>& ogl) \r
, renderer_(ogl)\r
, transform_stack_(1) \r
{\r
+ CASPAR_LOG(info) << L"Initialized OpenGL Accelerated GPU Image Mixer";\r
}\r
\r
void begin_layer(core::blend_mode blend_mode)\r
layers_.push_back(layer(std::vector<item>(), blend_mode));\r
}\r
\r
- void push(core::frame_transform& transform)\r
+ void push(const core::frame_transform& transform)\r
{\r
- transform_stack_.push_back(transform_stack_.back()*transform);\r
+ transform_stack_.push_back(transform_stack_.back()*transform.image_transform);\r
}\r
\r
- void visit(core::data_frame& frame2)\r
+ void visit(const core::data_frame& frame2)\r
{ \r
- write_frame* frame = dynamic_cast<write_frame*>(&frame2);\r
+ auto frame = dynamic_cast<const data_frame*>(&frame2);\r
if(frame == nullptr)\r
return;\r
\r
- if(frame->get_pixel_format_desc().format == core::pixel_format::invalid)\r
+ if(frame->pixel_format_desc().format == core::pixel_format::invalid)\r
return;\r
\r
- if(frame->get_buffers().empty())\r
+ if(frame->buffers().empty())\r
return;\r
\r
if(transform_stack_.back().field_mode == core::field_mode::empty)\r
return;\r
\r
item item;\r
- item.pix_desc = frame->get_pixel_format_desc();\r
- item.buffers = frame->get_buffers(); \r
+ item.pix_desc = frame->pixel_format_desc();\r
+ item.field_mode = frame->field_mode();\r
+ item.buffers = frame->buffers(); \r
item.transform = transform_stack_.back();\r
- item.transform.volume = core::frame_transform().volume; // Set volume to default since we don't care about it here.\r
\r
layers_.back().items.push_back(item);\r
}\r
return renderer_(std::move(layers_), format_desc);\r
}\r
\r
- virtual spl::shared_ptr<ogl::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
+ virtual spl::shared_ptr<core::data_frame> create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode)\r
{\r
- return spl::make_shared<ogl::write_frame>(ogl_, tag, desc);\r
+ return spl::make_shared<ogl::data_frame>(ogl_, tag, desc, frame_rate, field_mode);\r
}\r
};\r
\r
image_mixer::image_mixer(const spl::shared_ptr<context>& ogl) : impl_(new impl(ogl)){}\r
-void image_mixer::push(core::frame_transform& transform){impl_->push(transform);}\r
-void image_mixer::visit(core::data_frame& frame){impl_->visit(frame);}\r
+void image_mixer::push(const core::frame_transform& transform){impl_->push(transform);}\r
+void image_mixer::visit(const core::data_frame& frame){impl_->visit(frame);}\r
void image_mixer::pop(){impl_->pop();}\r
boost::shared_future<boost::iterator_range<const uint8_t*>> image_mixer::operator()(const core::video_format_desc& format_desc){return impl_->render(format_desc);}\r
void image_mixer::begin_layer(core::blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
void image_mixer::end_layer(){impl_->end_layer();}\r
-spl::shared_ptr<core::write_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc) {return impl_->create_frame(tag, desc);}\r
+spl::shared_ptr<core::data_frame> image_mixer::create_frame(const void* tag, const core::pixel_format_desc& desc, double frame_rate, core::field_mode field_mode) {return impl_->create_frame(tag, desc, frame_rate, field_mode);}\r
\r
}}}
\ No newline at end of file