]> git.sesse.net Git - casparcg/blobdiff - mixer/frame_mixer_device.cpp
2.0.0.2: Added channel wise mixer animations.
[casparcg] / mixer / frame_mixer_device.cpp
index 2bddca4f0f70139b953c0f0439105af32c02a095..8aac798f7c66cf1f3caf59a9885f8d9efef0b031 100644 (file)
@@ -12,6 +12,7 @@
 #include <common/exception/exceptions.h>\r
 #include <common/concurrency/executor.h>\r
 #include <common/diagnostics/graph.h>\r
+#include <common/utility/assert.h>\r
 #include <common/utility/timer.h>\r
 #include <common/gl/gl_check.h>\r
 \r
 \r
 namespace caspar { namespace core {\r
        \r
+       \r
+template<typename T>\r
+class basic_animated_value\r
+{\r
+       T source_;\r
+       T dest_;\r
+       int duration_;\r
+       int time_;\r
+public:        \r
+       basic_animated_value()\r
+               : duration_(0)\r
+               , time_(0){}\r
+       basic_animated_value(const T& dest)\r
+               : source_(dest)\r
+               , dest_(dest)\r
+               , duration_(0)\r
+               , time_(0){}\r
+\r
+       basic_animated_value(const T& source, const T& dest, int duration)\r
+               : source_(source)\r
+               , dest_(dest)\r
+               , duration_(duration)\r
+               , time_(0){}\r
+       \r
+       virtual T fetch()\r
+       {\r
+               return lerp(source_, dest_, duration_ < 1 ? 1.0f : static_cast<float>(time_)/static_cast<float>(duration_));\r
+       }\r
+       virtual T fetch_and_tick(int num)\r
+       {                                               \r
+               time_ = std::min(time_+num, duration_);\r
+               return fetch();\r
+       }\r
+};\r
+\r
 struct frame_mixer_device::implementation : boost::noncopyable\r
 {              \r
+       const printer                   parent_printer_;\r
        const video_format_desc format_desc_;\r
 \r
        safe_ptr<diagnostics::graph> graph_;\r
@@ -42,38 +79,40 @@ struct frame_mixer_device::implementation : boost::noncopyable
        std::unordered_map<int, image_transform> image_transforms_;\r
        std::unordered_map<int, audio_transform> audio_transforms_;\r
 \r
+       basic_animated_value<image_transform> root_image_transform_;\r
+       basic_animated_value<audio_transform> root_audio_transform_;\r
+\r
        executor executor_;\r
 public:\r
-       implementation(const video_format_desc& format_desc, const output_func& output) \r
-               : format_desc_(format_desc)\r
+       implementation(const printer& parent_printer, const video_format_desc& format_desc, const output_func& output) \r
+               : parent_printer_(parent_printer)\r
+               , format_desc_(format_desc)\r
                , graph_(diagnostics::create_graph(narrow(print())))\r
                , image_mixer_(format_desc)\r
                , output_(output)\r
-               , executor_(L"frame_mixer_device")\r
+               , executor_(print())\r
        {\r
                graph_->guide("frame-time", 0.5f);      \r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
                graph_->set_color("tick-time", diagnostics::color(0.1f, 0.7f, 0.8f));\r
-               graph_->set_color("output-buffer", diagnostics::color( 0.0f, 1.0f, 0.0f));              \r
+               graph_->set_color("input-buffer", diagnostics::color(1.0f, 1.0f, 0.0f));                \r
                executor_.start();\r
                executor_.set_capacity(2);\r
                CASPAR_LOG(info) << print() << L" Successfully initialized.";   \r
        }\r
                \r
-       ~implementation()\r
-       {\r
-               CASPAR_LOG(info) << print() << L" Shutting down.";      \r
-       }\r
-\r
        void send(const std::vector<safe_ptr<draw_frame>>& frames)\r
        {                       \r
                executor_.begin_invoke([=]\r
                {\r
+                       int num = format_desc_.mode == video_mode::progressive ? 1 : 2;\r
+\r
                        perf_timer_.reset();\r
                        auto image = image_mixer_.begin_pass();\r
                        BOOST_FOREACH(auto& frame, frames)\r
                        {\r
-                               image_mixer_.begin(image_transforms_[frame->get_layer_index()]);\r
+                               auto transform = root_image_transform_.fetch_and_tick(num)*image_transforms_[frame->get_layer_index()];\r
+                               image_mixer_.begin(transform);\r
                                frame->process_image(image_mixer_);\r
                                image_mixer_.end();\r
                        }\r
@@ -82,54 +121,104 @@ public:
                        auto audio = audio_mixer_.begin_pass();\r
                        BOOST_FOREACH(auto& frame, frames)\r
                        {\r
-                               audio_mixer_.begin(audio_transforms_[frame->get_layer_index()]);\r
+                               auto transform = root_audio_transform_.fetch_and_tick(num)*audio_transforms_[frame->get_layer_index()];\r
+                               audio_mixer_.begin(transform);\r
                                frame->process_audio(audio_mixer_);\r
                                audio_mixer_.end();\r
                        }\r
                        audio_mixer_.end_pass();\r
+\r
                        graph_->update("frame-time", static_cast<float>(perf_timer_.elapsed()/format_desc_.interval*0.5));\r
 \r
                        output_(make_safe<const read_frame>(std::move(image.get()), std::move(audio)));\r
                        graph_->update("tick-time", static_cast<float>(wait_perf_timer_.elapsed()/format_desc_.interval*0.5));\r
                        wait_perf_timer_.reset();\r
 \r
-                       graph_->set("output-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
+                       graph_->set("input-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
                });\r
-               graph_->set("output-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
+               graph_->set("input-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
        }\r
                \r
        safe_ptr<write_frame> create_frame(const pixel_format_desc& desc)\r
        {\r
                return make_safe<write_frame>(desc, image_mixer_.create_buffers(desc));\r
        }\r
-               \r
-       image_transform get_image_transform(int index)\r
+                               \r
+       void set_image_transform(const image_transform& transform, int)\r
        {\r
-               return executor_.invoke([&]{return image_transforms_[index];});\r
+               executor_.invoke([&]\r
+               {\r
+                       root_image_transform_ = transform;\r
+               });\r
        }\r
 \r
-       audio_transform get_audio_transform(int index)\r
+       void set_audio_transform(const audio_transform& transform, int)\r
        {\r
-               return executor_.invoke([&]{return audio_transforms_[index];});\r
+               executor_.invoke([&]\r
+               {\r
+                       root_audio_transform_ = transform;\r
+               });\r
        }\r
 \r
-       void set_image_transform(int index, image_transform&& transform)\r
+       void set_image_transform(int index, const image_transform& transform, int)\r
        {\r
-               return executor_.invoke([&]{image_transforms_[index] = std::move(transform);});\r
+               executor_.invoke([&]\r
+               {\r
+                       image_transforms_[index] = transform;\r
+               });\r
        }\r
 \r
-       void set_audio_transform(int index, audio_transform&& transform)\r
+       void set_audio_transform(int index, const audio_transform& transform, int)\r
        {\r
-               return executor_.invoke([&]{audio_transforms_[index] = std::move(transform);});\r
+               executor_.invoke([&]\r
+               {\r
+                       audio_transforms_[index] = transform;\r
+               });\r
+       }\r
+       \r
+       void apply_image_transform(const std::function<image_transform(const image_transform&)>& transform, int mix_duration)\r
+       {\r
+               return executor_.invoke([&]\r
+               {\r
+                       auto src = root_image_transform_.fetch();\r
+                       auto dst = transform(src);\r
+                       root_image_transform_ = basic_animated_value<image_transform>(src, dst, mix_duration);\r
+               });\r
+       }\r
+\r
+       void apply_audio_transform(const std::function<audio_transform(audio_transform)>& transform, int mix_duration)\r
+       {\r
+               return executor_.invoke([&]\r
+               {\r
+                       auto src = root_audio_transform_.fetch();\r
+                       auto dst = transform(src);\r
+                       root_audio_transform_ = basic_animated_value<audio_transform>(src, dst, mix_duration);\r
+               });\r
+       }\r
+\r
+       void apply_image_transform(int index, const std::function<image_transform(image_transform)>& transform, int)\r
+       {\r
+               executor_.invoke([&]\r
+               {\r
+                       image_transforms_[index] = transform(image_transforms_[index]);\r
+               });\r
+       }\r
+\r
+       void apply_audio_transform(int index, const std::function<audio_transform(audio_transform)>& transform, int)\r
+       {\r
+               executor_.invoke([&]\r
+               {\r
+                       audio_transforms_[index] = transform(audio_transforms_[index]);\r
+               });\r
        }\r
 \r
        std::wstring print() const\r
        {\r
-               return L"Video/Audio Mixer [" + format_desc_.name + L"]";\r
+               return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"mixer";\r
        }\r
 };\r
        \r
-frame_mixer_device::frame_mixer_device(const video_format_desc& format_desc, const output_func& output) : impl_(new implementation(format_desc, output)){}\r
+frame_mixer_device::frame_mixer_device(const printer& parent_printer, const video_format_desc& format_desc, const output_func& output) : impl_(new implementation(parent_printer, format_desc, output)){}\r
 frame_mixer_device::frame_mixer_device(frame_mixer_device&& other) : impl_(std::move(other.impl_)){}\r
 void frame_mixer_device::send(const std::vector<safe_ptr<draw_frame>>& frames){impl_->send(frames);}\r
 const video_format_desc& frame_mixer_device::get_video_format_desc() const { return impl_->format_desc_; }\r
@@ -151,9 +240,13 @@ safe_ptr<write_frame> frame_mixer_device::create_frame(pixel_format::type pix_fm
        desc.planes.push_back(pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4));\r
        return create_frame(desc);\r
 }\r
-image_transform frame_mixer_device::get_image_transform(int index){return impl_->get_image_transform(index);}\r
-audio_transform frame_mixer_device::get_audio_transform(int index){return impl_->get_audio_transform(index);}\r
-void frame_mixer_device::set_image_transform(int index, image_transform&& transform){impl_->set_image_transform(index, std::move(transform));}\r
-void frame_mixer_device::set_audio_transform(int index, audio_transform&& transform){impl_->set_audio_transform(index, std::move(transform));}\r
+void frame_mixer_device::set_image_transform(const image_transform& transform, int mix_duration){impl_->set_image_transform(transform, mix_duration);}\r
+void frame_mixer_device::set_image_transform(int index, const image_transform& transform, int mix_duration){impl_->set_image_transform(index, transform, mix_duration);}\r
+void frame_mixer_device::set_audio_transform(const audio_transform& transform, int mix_duration){impl_->set_audio_transform(transform, mix_duration);}\r
+void frame_mixer_device::set_audio_transform(int index, const audio_transform& transform, int mix_duration){impl_->set_audio_transform(index, transform, mix_duration);}\r
+void frame_mixer_device::apply_image_transform(const std::function<image_transform(image_transform)>& transform, int mix_duration ){impl_->apply_image_transform(transform, mix_duration);}\r
+void frame_mixer_device::apply_image_transform(int index, const std::function<image_transform(image_transform)>& transform, int mix_duration){impl_->apply_image_transform(index, transform, mix_duration);}\r
+void frame_mixer_device::apply_audio_transform(const std::function<audio_transform(audio_transform)>& transform, int mix_duration){impl_->apply_audio_transform(transform, mix_duration);}\r
+void frame_mixer_device::apply_audio_transform(int index, const std::function<audio_transform(audio_transform)>& transform, int mix_duration ){impl_->apply_audio_transform(index, transform, mix_duration);}\r
 \r
 }}
\ No newline at end of file