#include <unordered_map>\r
\r
namespace caspar { namespace core {\r
-\r
-template<typename T>\r
-struct animated_value\r
-{\r
- virtual T fetch() = 0;\r
- virtual T fetch_and_tick(bool& done) = 0;\r
- T fetch_and_tick()\r
- {\r
- bool dummy;\r
- return fetch_and_tick(dummy);\r
- }\r
-\r
- virtual safe_ptr<animated_value<T>> source() = 0;\r
- virtual safe_ptr<animated_value<T>> dest() = 0;\r
-};\r
-\r
-template<typename T>\r
-class basic_animated_value : public animated_value<T>\r
-{\r
- T current_;\r
-public:\r
- basic_animated_value(){}\r
- basic_animated_value(const T& current) : current_(current){}\r
\r
- virtual T fetch(){return current_;}\r
- virtual T fetch_and_tick(bool& done)\r
- {\r
- done = false;\r
- return current_;\r
- }\r
-\r
- virtual safe_ptr<animated_value<T>> source() {return make_safe<basic_animated_value<T>>(current_);}\r
- virtual safe_ptr<animated_value<T>> dest() {return make_safe<basic_animated_value<T>>(current_);}\r
-};\r
- \r
-template<typename T>\r
-class nested_animated_value : public animated_value<T>\r
-{\r
- safe_ptr<animated_value<T>> source_;\r
- safe_ptr<animated_value<T>> dest_;\r
- const int duration_;\r
- int time_;\r
-public:\r
- nested_animated_value()\r
- : source_(basic_animated_value<T>())\r
- , dest_(basic_animated_value<T>())\r
- , duration_(duration)\r
- , time_(0){}\r
- nested_animated_value(const safe_ptr<animated_value<T>>& source, const safe_ptr<animated_value<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_->fetch(), dest_->fetch(), duration_ < 1 ? 1.0f : static_cast<float>(time_)/static_cast<float>(duration_));\r
- }\r
- virtual T fetch_and_tick(bool& done)\r
- {\r
- done = time_ >= duration_;\r
-\r
- bool src_done = false;\r
- auto src = source_->fetch_and_tick(src_done);\r
- if(src_done)\r
- source_ = source_->dest();\r
- \r
- bool dst_done = false;\r
- auto dst = dest_->fetch_and_tick(dst_done);\r
- if(dst_done)\r
- dest_ = dest_->dest();\r
- \r
- time_ = std::min(time_+1, duration_);\r
- return lerp(src, dst, duration_ < 1 ? 1.0f : (static_cast<float>(time_)/static_cast<float>(duration_)));\r
- }\r
-\r
- virtual safe_ptr<animated_value<T>> source() {return source_;}\r
- virtual safe_ptr<animated_value<T>> dest() {return dest_;}\r
-};\r
-\r
struct frame_mixer_device::implementation : boost::noncopyable\r
{ \r
const printer parent_printer_;\r
std::unordered_map<int, audio_transform> audio_transforms_;\r
\r
image_transform root_image_transform_;\r
- safe_ptr<animated_value<audio_transform>> root_audio_transform_;\r
+ audio_transform root_audio_transform_;\r
\r
executor executor_;\r
public:\r
, image_mixer_(format_desc)\r
, output_(output)\r
, executor_(print())\r
- , root_audio_transform_(basic_animated_value<audio_transform>())\r
{\r
graph_->guide("frame-time", 0.5f); \r
graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
auto audio = audio_mixer_.begin_pass();\r
BOOST_FOREACH(auto& frame, frames)\r
{\r
- audio_mixer_.begin(root_audio_transform_->fetch_and_tick()*audio_transforms_[frame->get_layer_index()]);\r
+ audio_mixer_.begin(root_audio_transform_*audio_transforms_[frame->get_layer_index()]);\r
frame->process_audio(audio_mixer_);\r
audio_mixer_.end();\r
}\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
+ executor_.invoke([&]\r
+ {\r
+ root_image_transform_ = transform;\r
+ });\r
+ }\r
+\r
+ void set_audio_transform(const audio_transform& transform, int)\r
+ {\r
+ executor_.invoke([&]\r
+ {\r
+ root_audio_transform_ = transform;\r
+ });\r
+ }\r
+\r
+ void set_image_transform(int index, const image_transform& transform, int)\r
{\r
- return executor_.invoke([&]{return image_transforms_[index];});\r
+ executor_.invoke([&]\r
+ {\r
+ image_transforms_[index] = transform;\r
+ });\r
}\r
\r
- audio_transform get_audio_transform(int index)\r
+ void set_audio_transform(int index, const audio_transform& transform, int)\r
{\r
- return executor_.invoke([&]{return audio_transforms_[index];});\r
+ executor_.invoke([&]\r
+ {\r
+ audio_transforms_[index] = transform;\r
+ });\r
}\r
\r
- void set_image_transform(const image_transform& transform, int mix_duration)\r
+ void apply_image_transform(const std::function<image_transform(const image_transform&)> transform, int)\r
{\r
return executor_.invoke([&]\r
{\r
- root_image_transform_ = root_image_transform_;\r
+ root_image_transform_ = transform(root_image_transform_);\r
});\r
}\r
\r
- void set_audio_transform(const audio_transform& transform, int mix_duration)\r
+ void apply_audio_transform(const std::function<audio_transform(audio_transform)> transform, int)\r
{\r
return executor_.invoke([&]\r
{\r
- root_audio_transform_ = make_safe<nested_animated_value<audio_transform>>(root_audio_transform_, make_safe<basic_animated_value<audio_transform>>(transform), mix_duration);\r
+ root_audio_transform_ = transform(root_audio_transform_);\r
});\r
}\r
\r
- void set_image_transform(int index, const image_transform& transform, int mix_duration)\r
+ void apply_image_transform(int index, const std::function<image_transform(image_transform)> transform, int)\r
{\r
- return executor_.invoke([&]\r
+ executor_.invoke([&]\r
{\r
- image_transforms_[index] = transform;\r
+ image_transforms_[index] = transform(image_transforms_[index]);\r
});\r
}\r
\r
- void set_audio_transform(int index, const audio_transform& transform, int mix_duration)\r
+ void apply_audio_transform(int index, const std::function<audio_transform(audio_transform)> transform, int)\r
{\r
- return executor_.invoke([&]\r
+ executor_.invoke([&]\r
{\r
- audio_transforms_[index] = transform;\r
+ audio_transforms_[index] = transform(audio_transforms_[index]);\r
});\r
}\r
\r
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(const image_transform& transform, int mix_duration){impl_->set_image_transform(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_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
\r
const video_format_desc& get_video_format_desc() const; // nothrow\r
\r
- image_transform get_image_transform(int index);\r
- audio_transform get_audio_transform(int index);\r
- \r
void set_image_transform(const image_transform& transform, int mix_duration = 0);\r
- void set_audio_transform(const audio_transform& transform, int mix_duration = 0);\r
void set_image_transform(int index, const image_transform& transform, int mix_duration = 0);\r
+\r
+ void set_audio_transform(const audio_transform& transform, int mix_duration = 0);\r
void set_audio_transform(int index, const audio_transform& transform, int mix_duration = 0);\r
+ \r
+ void apply_image_transform(const std::function<image_transform(image_transform)>& transform, int mix_duration = 0);\r
+ void apply_image_transform(int index, const std::function<image_transform(image_transform)>& transform, int mix_duration = 0);\r
+\r
+ void apply_audio_transform(const std::function<audio_transform(audio_transform)>& transform, int mix_duration = 0);\r
+ void apply_audio_transform(int index, const std::function<audio_transform(audio_transform)>& transform, int mix_duration = 0);\r
\r
private:\r
struct implementation;\r
{\r
int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[2], 0) : 0;\r
double value = boost::lexical_cast<double>(_parameters.at(2));\r
- auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
- transform.set_opacity(value);\r
+ \r
+ auto transform = [=](image_transform transform) -> image_transform\r
+ {\r
+ transform.set_opacity(value);\r
+ return transform; \r
+ };\r
\r
int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
if(layer != std::numeric_limits<int>::min()) \r
- GetChannel()->mixer().set_image_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(GetLayerIndex(), transform, duration);\r
else\r
- GetChannel()->mixer().set_image_transform(transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(transform, duration);\r
}\r
else if(_parameters[1] == L"GAIN")\r
{\r
int duration = _parameters.size() > 2 ? lexical_cast_or_default(_parameters[2], 0) : 0;\r
double value = boost::lexical_cast<double>(_parameters.at(2));\r
- auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
- transform.set_gain(value);\r
+ \r
+ auto transform = [=](image_transform transform) -> image_transform\r
+ {\r
+ transform.set_gain(value);\r
+ return transform; \r
+ };\r
\r
int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
if(layer != std::numeric_limits<int>::min())\r
- GetChannel()->mixer().set_image_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(GetLayerIndex(), transform, duration);\r
else\r
- GetChannel()->mixer().set_image_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(transform, duration);\r
}\r
else if(_parameters[1] == L"FILL_RECT")\r
{\r
double y = boost::lexical_cast<double>(_parameters.at(3));\r
double x_s = boost::lexical_cast<double>(_parameters.at(4));\r
double y_s = boost::lexical_cast<double>(_parameters.at(5));\r
- auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
- transform.set_fill_translation(x, y);\r
- transform.set_fill_scale(x_s, y_s);\r
- transform.set_key_translation(x, y);\r
- transform.set_key_scale(x_s, y_s);\r
+\r
+ auto transform = [=](image_transform transform) -> image_transform\r
+ {\r
+ transform.set_fill_translation(x, y);\r
+ transform.set_fill_scale(x_s, y_s);\r
+ transform.set_key_translation(x, y);\r
+ transform.set_key_scale(x_s, y_s);\r
+ return transform;\r
+ };\r
\r
int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
if(layer != std::numeric_limits<int>::min())\r
- GetChannel()->mixer().set_image_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(GetLayerIndex(), transform, duration);\r
else\r
- GetChannel()->mixer().set_image_transform(transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(transform, duration);\r
}\r
else if(_parameters[1] == L"KEY_RECT")\r
{\r
double y = boost::lexical_cast<double>(_parameters.at(3));\r
double x_s = boost::lexical_cast<double>(_parameters.at(4));\r
double y_s = boost::lexical_cast<double>(_parameters.at(5));\r
- auto transform = GetChannel()->mixer().get_image_transform(GetLayerIndex());\r
- transform.set_fill_translation(0.0, 0.0);\r
- transform.set_fill_scale(1.0, 1.0);\r
- transform.set_key_translation(x, y);\r
- transform.set_key_scale(x_s, y_s);\r
+\r
+ auto transform = [=](image_transform transform) -> image_transform\r
+ {\r
+ transform.set_fill_translation(0.0, 0.0);\r
+ transform.set_fill_scale(1.0, 1.0);\r
+ transform.set_key_translation(x, y);\r
+ transform.set_key_scale(x_s, y_s);\r
+ return transform;\r
+ };\r
\r
int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
if(layer != std::numeric_limits<int>::min())\r
- GetChannel()->mixer().set_image_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(GetLayerIndex(), transform, duration);\r
else\r
- GetChannel()->mixer().set_image_transform(transform, duration);\r
+ GetChannel()->mixer().apply_image_transform(transform, duration);\r
}\r
else if(_parameters[1] == L"GRID")\r
{\r
for(int y = 0; y < n; ++y)\r
{\r
int index = x+y*n;\r
- auto transform = GetChannel()->mixer().get_image_transform(index); \r
- transform.set_fill_translation(x*delta, y*delta);\r
- transform.set_fill_scale(delta, delta); \r
- transform.set_key_translation(x*delta, y*delta);\r
- transform.set_key_scale(delta, delta);\r
- GetChannel()->mixer().set_image_transform(index, transform, 0);\r
+ auto transform = [=](image_transform transform) -> image_transform\r
+ { \r
+ transform.set_fill_translation(x*delta, y*delta);\r
+ transform.set_fill_scale(delta, delta); \r
+ transform.set_key_translation(x*delta, y*delta);\r
+ transform.set_key_scale(delta, delta);\r
+ return transform;\r
+ };\r
+ GetChannel()->mixer().apply_image_transform(index, transform, 0);\r
}\r
}\r
}\r
{\r
int duration = _parameters.size() > 3 ? lexical_cast_or_default(_parameters[3], 0) : 0;\r
double value = boost::lexical_cast<double>(_parameters[2]);\r
- auto transform = GetChannel()->mixer().get_audio_transform(GetLayerIndex());\r
- transform.set_gain(value);\r
\r
+ auto transform = [=](audio_transform transform) -> audio_transform\r
+ {\r
+ transform.set_gain(value);\r
+ return transform;\r
+ };\r
+ \r
int layer = GetLayerIndex(std::numeric_limits<int>::min());\r
if(layer != std::numeric_limits<int>::min())\r
- GetChannel()->mixer().set_audio_transform(GetLayerIndex(), transform, duration);\r
+ GetChannel()->mixer().apply_audio_transform(GetLayerIndex(), transform, duration);\r
else\r
- GetChannel()->mixer().set_audio_transform(transform, duration);\r
+ GetChannel()->mixer().apply_audio_transform(transform, duration);\r
}\r
else if(_parameters[1] == L"RESET")\r
{\r