#include "gpu/gpu_read_frame.h"\r
#include "gpu/gpu_write_frame.h"\r
\r
-#include <core/producer/frame/audio_transform.h>\r
-#include <core/producer/frame/image_transform.h>\r
-\r
#include "audio/audio_mixer.h"\r
#include "image/image_mixer.h"\r
\r
#include <common/utility/timer.h>\r
#include <common/utility/tweener.h>\r
\r
+#include <core/producer/frame/audio_transform.h>\r
+#include <core/producer/frame/image_transform.h>\r
+\r
#include <core/video_format.h>\r
\r
+#include <boost/fusion/container/map.hpp>\r
+#include <boost/fusion/include/at_key.hpp>\r
+\r
#include <unordered_map>\r
\r
namespace caspar { namespace mixer {\r
, time_(0)\r
, tweener_(get_tweener(tween)){}\r
\r
- virtual T fetch()\r
+ T fetch()\r
{\r
- return tween(static_cast<double>(time_), source_, dest_, static_cast<double>(duration_)+0.000001, tweener_);\r
+ return time_ == duration_ ? dest_ : tween(static_cast<double>(time_), source_, dest_, static_cast<double>(duration_), tweener_);\r
}\r
- virtual T fetch_and_tick(int num)\r
+\r
+ T fetch_and_tick(int num)\r
{ \r
time_ = std::min(time_+num, duration_);\r
return fetch();\r
image_mixer image_mixer_;\r
\r
output_t output_;\r
+ \r
+ typedef std::unordered_map<int, tweened_transform<core::image_transform>> image_transforms;\r
+ typedef std::unordered_map<int, tweened_transform<core::audio_transform>> audio_transforms;\r
\r
- std::unordered_map<int, tweened_transform<core::image_transform>> image_transforms_;\r
- std::unordered_map<int, tweened_transform<core::audio_transform>> audio_transforms_;\r
-\r
- tweened_transform<core::image_transform> root_image_transform_;\r
- tweened_transform<core::audio_transform> root_audio_transform_;\r
+ boost::fusion::map<boost::fusion::pair<core::image_transform, image_transforms>,\r
+ boost::fusion::pair<core::audio_transform, audio_transforms>> transforms_;\r
+ \r
+ boost::fusion::map<boost::fusion::pair<core::image_transform, tweened_transform<core::image_transform>>,\r
+ boost::fusion::pair<core::audio_transform, tweened_transform<core::audio_transform>>> root_transforms_;\r
\r
executor executor_;\r
public:\r
: format_desc_(format_desc)\r
, diag_(diagnostics::create_graph(narrow(print())))\r
, image_mixer_(format_desc)\r
- , executor_(print())\r
+ , executor_(L"frame_mixer_device")\r
{\r
diag_->add_guide("frame-time", 0.5f); \r
diag_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
{\r
frames.erase(std::remove(frames.begin(), frames.end(), core::basic_frame::empty()), frames.end());\r
frames.erase(std::remove(frames.begin(), frames.end(), core::basic_frame::eof()), frames.end());\r
+ \r
+ auto& root_image_transform = boost::fusion::at_key<core::image_transform>(root_transforms_);\r
+ auto& image_transforms = boost::fusion::at_key<core::image_transform>(transforms_);\r
\r
auto image = image_mixer_.begin_pass();\r
BOOST_FOREACH(auto& frame, frames)\r
{\r
auto frame1 = make_safe<core::basic_frame>(frame);\r
auto frame2 = make_safe<core::basic_frame>(frame);\r
-\r
- frame1->get_image_transform() = root_image_transform_.fetch_and_tick(1)*image_transforms_[frame->get_layer_index()].fetch_and_tick(1);\r
- frame2->get_image_transform() = root_image_transform_.fetch_and_tick(1)*image_transforms_[frame->get_layer_index()].fetch_and_tick(1);\r
+ \r
+ frame1->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame->get_layer_index()].fetch_and_tick(1);\r
+ frame2->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame->get_layer_index()].fetch_and_tick(1);\r
\r
if(frame1->get_image_transform() != frame2->get_image_transform())\r
core::basic_frame::interlace(frame1, frame2, format_desc_.mode)->accept(image_mixer_);\r
else\r
{\r
auto frame1 = make_safe<core::basic_frame>(frame);\r
- frame1->get_image_transform() = root_image_transform_.fetch_and_tick(1)*image_transforms_[frame->get_layer_index()].fetch_and_tick(1);\r
+ frame1->get_image_transform() = root_image_transform.fetch_and_tick(1)*image_transforms[frame->get_layer_index()].fetch_and_tick(1);\r
frame1->accept(image_mixer_);\r
}\r
}\r
\r
std::vector<short> mix_audio(const std::vector<safe_ptr<core::basic_frame>>& frames)\r
{\r
+ auto& root_audio_transform = boost::fusion::at_key<core::audio_transform>(root_transforms_);\r
+ auto& audio_transforms = boost::fusion::at_key<core::audio_transform>(transforms_);\r
+\r
auto audio = audio_mixer_.begin_pass();\r
BOOST_FOREACH(auto& frame, frames)\r
{\r
int num = format_desc_.mode == core::video_mode::progressive ? 1 : 2;\r
\r
auto frame1 = make_safe<core::basic_frame>(frame);\r
- frame1->get_audio_transform() = root_audio_transform_.fetch_and_tick(num)*audio_transforms_[frame->get_layer_index()].fetch_and_tick(num);\r
+ frame1->get_audio_transform() = root_audio_transform.fetch_and_tick(num)*audio_transforms[frame->get_layer_index()].fetch_and_tick(num);\r
frame1->accept(audio_mixer_);\r
}\r
audio_mixer_.end_pass();\r
{\r
return make_safe<gpu_write_frame>(reinterpret_cast<int>(tag), desc, image_mixer_.create_buffers(desc));\r
}\r
- \r
- void set_image_transform(const core::image_transform& transform, int mix_duration, const std::wstring& tween)\r
+ \r
+ template<typename T> \r
+ void set_transform(const T& transform, int mix_duration, const std::wstring& tween)\r
{\r
executor_.invoke([&]\r
{\r
- auto src = root_image_transform_.fetch();\r
- auto dst = transform;\r
- root_image_transform_ = tweened_transform<core::image_transform>(src, dst, mix_duration, tween);\r
- });\r
- }\r
+ auto& root = boost::fusion::at_key<T>(root_transforms_);\r
\r
- void set_audio_transform(const core::audio_transform& transform, int mix_duration, const std::wstring& tween)\r
- {\r
- executor_.invoke([&]\r
- {\r
- auto src = root_audio_transform_.fetch();\r
+ auto src = root.fetch();\r
auto dst = transform;\r
- root_audio_transform_ = tweened_transform<core::audio_transform>(src, dst, mix_duration, tween);\r
+ root = tweened_transform<T>(src, dst, mix_duration, tween);\r
});\r
}\r
-\r
- void set_image_transform(int index, const core::image_transform& transform, int mix_duration, const std::wstring& tween)\r
+ \r
+ template<typename T>\r
+ void set_transform(int index, const T& transform, int mix_duration, const std::wstring& tween)\r
{\r
executor_.invoke([&]\r
{\r
- auto src = image_transforms_[index].fetch();\r
- auto dst = transform;\r
- image_transforms_[index] = tweened_transform<core::image_transform>(src, dst, mix_duration, tween);\r
- });\r
- }\r
+ auto& transforms = boost::fusion::at_key<T>(transforms_);\r
\r
- void set_audio_transform(int index, const core::audio_transform& transform, int mix_duration, const std::wstring& tween)\r
- {\r
- executor_.invoke([&]\r
- {\r
- auto src = audio_transforms_[index].fetch();\r
+ auto src = transforms[index].fetch();\r
auto dst = transform;\r
- audio_transforms_[index] = tweened_transform<core::audio_transform>(src, dst, mix_duration, tween);\r
+ transforms[index] = tweened_transform<T>(src, dst, mix_duration, tween);\r
});\r
}\r
- \r
- void apply_image_transform(const std::function<core::image_transform(const core::image_transform&)>& transform, int mix_duration, const std::wstring& tween)\r
+ \r
+ template<typename T>\r
+ void apply_transform(const std::function<T(const T&)>& transform, int mix_duration, const std::wstring& tween)\r
{\r
return executor_.invoke([&]\r
{\r
- auto src = root_image_transform_.fetch();\r
- auto dst = transform(src);\r
- root_image_transform_ = tweened_transform<core::image_transform>(src, dst, mix_duration, tween);\r
- });\r
- }\r
+ auto& root = boost::fusion::at_key<T>(root_transforms_);\r
\r
- void apply_audio_transform(const std::function<core::audio_transform(core::audio_transform)>& transform, int mix_duration, const std::wstring& tween)\r
- {\r
- return executor_.invoke([&]\r
- {\r
- auto src = root_audio_transform_.fetch();\r
+ auto src = root.fetch();\r
auto dst = transform(src);\r
- root_audio_transform_ = tweened_transform<core::audio_transform>(src, dst, mix_duration, tween);\r
+ root = tweened_transform<T>(src, dst, mix_duration, tween);\r
});\r
}\r
-\r
- void apply_image_transform(int index, const std::function<core::image_transform(core::image_transform)>& transform, int mix_duration, const std::wstring& tween)\r
+ \r
+ template<typename T>\r
+ void apply_transform(int index, const std::function<T(T)>& transform, int mix_duration, const std::wstring& tween)\r
{\r
executor_.invoke([&]\r
{\r
- auto src = image_transforms_[index].fetch();\r
- auto dst = transform(src);\r
- image_transforms_[index] = tweened_transform<core::image_transform>(src, dst, mix_duration, tween);\r
- });\r
- }\r
+ auto& transforms = boost::fusion::at_key<T>(transforms_);\r
\r
- void apply_audio_transform(int index, const std::function<core::audio_transform(core::audio_transform)>& transform, int mix_duration, const std::wstring& tween)\r
- {\r
- executor_.invoke([&]\r
- {\r
- auto src = audio_transforms_[index].fetch();\r
+ auto src = transforms[index].fetch();\r
auto dst = transform(src);\r
- audio_transforms_[index] = tweened_transform<core::audio_transform>(src, dst, mix_duration, tween);\r
+ transforms[index] = tweened_transform<T>(src, dst, mix_duration, tween);\r
});\r
}\r
\r
- void reset_image_transform(int mix_duration, const std::wstring& tween)\r
+ template<typename T>\r
+ void reset_transform(int mix_duration, const std::wstring& tween)\r
{\r
executor_.invoke([&]\r
{\r
- BOOST_FOREACH(auto& t, image_transforms_) \r
- t.second = tweened_transform<core::image_transform>(t.second.fetch(), core::image_transform(), mix_duration, tween); \r
- root_image_transform_ = tweened_transform<core::image_transform>(root_image_transform_.fetch(), core::image_transform(), mix_duration, tween);\r
+ auto& transforms = boost::fusion::at_key<T>(transforms_);\r
+\r
+ BOOST_FOREACH(auto& t, transforms) \r
+ t.second = tweened_transform<T>(t.second.fetch(), T(), mix_duration, tween); \r
+ set_transform(T(), mix_duration, tween);\r
});\r
}\r
\r
- void reset_audio_transform(int mix_duration, const std::wstring& tween)\r
+ template<typename T>\r
+ void reset_transform(int index, int mix_duration, const std::wstring& tween)\r
{\r
executor_.invoke([&]\r
- {\r
- BOOST_FOREACH(auto& t, audio_transforms_)\r
- t.second = tweened_transform<core::audio_transform>(t.second.fetch(), core::audio_transform(), mix_duration, tween);\r
- root_audio_transform_ = tweened_transform<core::audio_transform>(root_audio_transform_.fetch(), core::audio_transform(), mix_duration, tween);\r
+ { \r
+ set_transform(T(), mix_duration, tween);\r
});\r
}\r
-\r
+ \r
std::wstring print() const\r
{\r
return L"frame_mixer_device";\r
desc.planes.push_back( core::pixel_format_desc::plane(get_video_format_desc().width, get_video_format_desc().height, 4));\r
return create_frame(tag, desc);\r
}\r
-void frame_mixer_device::set_image_transform(const core::image_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_image_transform(transform, mix_duration, tween);}\r
-void frame_mixer_device::set_image_transform(int index, const core::image_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_image_transform(index, transform, mix_duration, tween);}\r
-void frame_mixer_device::set_audio_transform(const core::audio_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_audio_transform(transform, mix_duration, tween);}\r
-void frame_mixer_device::set_audio_transform(int index, const core::audio_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_audio_transform(index, transform, mix_duration, tween);}\r
-void frame_mixer_device::apply_image_transform(const std::function<core::image_transform(core::image_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_image_transform(transform, mix_duration, tween);}\r
-void frame_mixer_device::apply_image_transform(int index, const std::function<core::image_transform(core::image_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_image_transform(index, transform, mix_duration, tween);}\r
-void frame_mixer_device::apply_audio_transform(const std::function<core::audio_transform(core::audio_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_audio_transform(transform, mix_duration, tween);}\r
-void frame_mixer_device::apply_audio_transform(int index, const std::function<core::audio_transform(core::audio_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_audio_transform(index, transform, mix_duration, tween);}\r
-void frame_mixer_device::reset_image_transform(int mix_duration, const std::wstring& tween){impl_->reset_image_transform(mix_duration, tween);}\r
-void frame_mixer_device::reset_audio_transform(int mix_duration, const std::wstring& tween){impl_->reset_audio_transform(mix_duration, tween);}\r
+void frame_mixer_device::set_image_transform(const core::image_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_transform<core::image_transform>(transform, mix_duration, tween);}\r
+void frame_mixer_device::set_image_transform(int index, const core::image_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_transform<core::image_transform>(index, transform, mix_duration, tween);}\r
+void frame_mixer_device::set_audio_transform(const core::audio_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_transform<core::audio_transform>(transform, mix_duration, tween);}\r
+void frame_mixer_device::set_audio_transform(int index, const core::audio_transform& transform, int mix_duration, const std::wstring& tween){impl_->set_transform<core::audio_transform>(index, transform, mix_duration, tween);}\r
+void frame_mixer_device::apply_image_transform(const std::function<core::image_transform(core::image_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_transform<core::image_transform>(transform, mix_duration, tween);}\r
+void frame_mixer_device::apply_image_transform(int index, const std::function<core::image_transform(core::image_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_transform<core::image_transform>(index, transform, mix_duration, tween);}\r
+void frame_mixer_device::apply_audio_transform(const std::function<core::audio_transform(core::audio_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_transform<core::audio_transform>(transform, mix_duration, tween);}\r
+void frame_mixer_device::apply_audio_transform(int index, const std::function<core::audio_transform(core::audio_transform)>& transform, int mix_duration, const std::wstring& tween){impl_->apply_transform<core::audio_transform>(index, transform, mix_duration, tween);}\r
+void frame_mixer_device::reset_image_transform(int mix_duration, const std::wstring& tween){impl_->reset_transform<core::image_transform>(mix_duration, tween);}\r
+void frame_mixer_device::reset_image_transform(int index, int mix_duration, const std::wstring& tween){impl_->reset_transform<core::image_transform>(index, mix_duration, tween);}\r
+void frame_mixer_device::reset_audio_transform(int mix_duration, const std::wstring& tween){impl_->reset_transform<core::audio_transform>(mix_duration, tween);}\r
+void frame_mixer_device::reset_audio_transform(int index, int mix_duration, const std::wstring& tween){impl_->reset_transform<core::audio_transform>(index, mix_duration, tween);}\r
\r
}}
\ No newline at end of file
{\r
if(_parameters[1] == L"OPACITY")\r
{\r
- int duration = _parameters.size() > 3 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
- std::wstring tween = _parameters.size() > 4 ? _parameters[4] : L"linear";\r
+ int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
+ std::wstring tween = _parameters.size() > 3 ? _parameters[4] : L"linear";\r
\r
double value = boost::lexical_cast<double>(_parameters.at(2));\r
\r
}\r
else if(_parameters[1] == L"GAIN")\r
{\r
- int duration = _parameters.size() > 3 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
- std::wstring tween = _parameters.size() > 4 ? _parameters[4] : L"linear";\r
+ int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
+ std::wstring tween = _parameters.size() > 3 ? _parameters[4] : L"linear";\r
double value = boost::lexical_cast<double>(_parameters.at(2));\r
\r
auto transform = [=](image_transform transform) -> image_transform\r
}\r
else if(_parameters[1] == L"FILL_RECT")\r
{\r
- int duration = _parameters.size() > 6 ? lexical_cast_or_default(_parameters[6], 0) : 0;\r
- std::wstring tween = _parameters.size() > 7 ? _parameters[7] : L"linear";\r
+ int duration = _parameters.size() > 5 ? lexical_cast_or_default(_parameters[6], 0) : 0;\r
+ std::wstring tween = _parameters.size() > 6 ? _parameters[7] : L"linear";\r
double x = boost::lexical_cast<double>(_parameters.at(2));\r
double y = boost::lexical_cast<double>(_parameters.at(3));\r
double x_s = boost::lexical_cast<double>(_parameters.at(4));\r
}\r
else if(_parameters[1] == L"KEY_RECT")\r
{\r
- int duration = _parameters.size() > 6 ? lexical_cast_or_default(_parameters[6], 0) : 0;\r
- std::wstring tween = _parameters.size() > 7 ? _parameters[7] : L"linear";\r
+ int duration = _parameters.size() > 5 ? lexical_cast_or_default(_parameters[6], 0) : 0;\r
+ std::wstring tween = _parameters.size() > 6 ? _parameters[7] : L"linear";\r
double x = boost::lexical_cast<double>(_parameters.at(2));\r
double y = boost::lexical_cast<double>(_parameters.at(3));\r
double x_s = boost::lexical_cast<double>(_parameters.at(4));\r
}\r
else if(_parameters[1] == L"GRID")\r
{\r
- int duration = _parameters.size() > 3 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
- std::wstring tween = _parameters.size() > 4 ? _parameters[4] : L"linear";\r
+ int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
+ std::wstring tween = _parameters.size() > 3 ? _parameters[4] : L"linear";\r
int n = boost::lexical_cast<int>(_parameters.at(2));\r
double delta = 1.0/static_cast<double>(n);\r
for(int x = 0; x < n; ++x)\r
{\r
for(int y = 0; y < n; ++y)\r
{\r
- int index = x+y*n;\r
+ int index = x+y*n+1;\r
auto transform = [=](image_transform transform) -> image_transform\r
{ \r
transform.set_fill_translation(x*delta, y*delta);\r
else if(_parameters[1] == L"RESET")\r
{\r
int duration = _parameters.size() > 1 ? lexical_cast_or_default(_parameters[2], 0) : 0;\r
- GetChannel()->mixer()->reset_image_transform(duration);\r
+ std::wstring tween = _parameters.size() > 2 ? _parameters[3] : L"linear";\r
+\r
+ int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
+ if(layer != std::numeric_limits<int>::min())\r
+ GetChannel()->mixer()->reset_image_transform(GetLayerIndex(), duration, tween);\r
+ else\r
+ GetChannel()->mixer()->reset_image_transform(duration, tween);\r
}\r
}\r
else if(_parameters[0] == L"AUDIO")\r
{\r
if(_parameters[1] == L"GAIN")\r
{\r
- int duration = _parameters.size() > 3 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
+ int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
+ std::wstring tween = _parameters.size() > 3 ? _parameters[4] : L"linear";\r
double value = boost::lexical_cast<double>(_parameters[2]);\r
\r
auto transform = [=](audio_transform transform) -> audio_transform\r
\r
int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
if(layer != std::numeric_limits<int>::min())\r
- GetChannel()->mixer()->apply_audio_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer()->apply_audio_transform(GetLayerIndex(), transform, duration, tween);\r
else\r
- GetChannel()->mixer()->apply_audio_transform(transform, duration);\r
+ GetChannel()->mixer()->apply_audio_transform(transform, duration, tween);\r
}\r
else if(_parameters[1] == L"RESET")\r
{\r
int duration = _parameters.size() > 1 ? lexical_cast_or_default(_parameters[2], 0) : 0;\r
- GetChannel()->mixer()->reset_audio_transform(duration);\r
+ std::wstring tween = _parameters.size() > 2 ? _parameters[3] : L"linear";\r
+ GetChannel()->mixer()->reset_audio_transform(duration, tween);\r
}\r
}\r
else if(_parameters[0] == L"RESET")\r
{\r
int duration = _parameters.size() > 1 ? lexical_cast_or_default(_parameters[2], 0) : 0;\r
- GetChannel()->mixer()->reset_image_transform(duration);\r
- GetChannel()->mixer()->reset_audio_transform(duration);\r
+ std::wstring tween = _parameters.size() > 2 ? _parameters[3] : L"linear";\r
+ GetChannel()->mixer()->reset_image_transform(duration, tween);\r
+ GetChannel()->mixer()->reset_audio_transform(duration, tween);\r
}\r
\r
SetReplyString(TEXT("202 MIXER OK\r\n"));\r