]> git.sesse.net Git - casparcg/blobdiff - accelerator/ogl/image/image_mixer.cpp
2.1.0: Refactored away "write_frame", only "data_frame" and "draw_frame" are needed.
[casparcg] / accelerator / ogl / image / image_mixer.cpp
index d243d611af22376bd2b6c422f6fd1fec6f8ed4bd..b521d46b777dd363d2053f534431547fb9e6f419 100644 (file)
@@ -25,7 +25,7 @@
 \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
@@ -34,7 +34,7 @@
 #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
@@ -59,13 +59,14 @@ typedef boost::shared_future<spl::shared_ptr<device_buffer>> future_texture;
 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
@@ -111,13 +112,12 @@ class image_renderer
 {\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
@@ -149,7 +149,7 @@ private:
                           (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
@@ -254,10 +254,16 @@ private:
                                        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
@@ -292,7 +298,19 @@ private:
                                   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
@@ -344,7 +362,7 @@ private:
                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
@@ -363,7 +381,7 @@ struct image_mixer::impl : boost::noncopyable
 {      \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
@@ -371,6 +389,7 @@ public:
                , 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
@@ -378,31 +397,31 @@ public:
                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
@@ -427,19 +446,19 @@ public:
                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