X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Fstage.cpp;h=f5ee6d1ff47d5bd426385c3153a55c11578f5baf;hb=d98f3a050ee44466a37c495e4b7805b21551a8fc;hp=101c7a3c4cc5c8d4cffb61a201ed0acc8c908946;hpb=98d4f99a02b11b8be9f842c1dbc5655ebe4e3cef;p=casparcg diff --git a/core/producer/stage.cpp b/core/producer/stage.cpp index 101c7a3c4..f5ee6d1ff 100644 --- a/core/producer/stage.cpp +++ b/core/producer/stage.cpp @@ -25,191 +25,163 @@ #include "layer.h" -#include "frame/basic_frame.h" -#include "frame/frame_factory.h" +#include "../frame/draw_frame.h" +#include "../frame/frame_factory.h" #include +#include -#include +#include #include #include +#include +#include #include -#include - +#include #include +#include namespace caspar { namespace core { -template -class tweened_transform -{ - T source_; - T dest_; - int duration_; - int time_; - tweener_t tweener_; -public: - tweened_transform() - : duration_(0) - , time_(0) - , tweener_(get_tweener(L"linear")){} - tweened_transform(const T& source, const T& dest, int duration, const std::wstring& tween = L"linear") - : source_(source) - , dest_(dest) - , duration_(duration) - , time_(0) - , tweener_(get_tweener(tween)){} - - T fetch() - { - return time_ == duration_ ? dest_ : tween(static_cast(time_), source_, dest_, static_cast(duration_), tweener_); - } - - T fetch_and_tick(int num) - { - time_ = std::min(time_+num, duration_); - return fetch(); - } -}; - -struct stage::implementation : public std::enable_shared_from_this - , boost::noncopyable -{ - safe_ptr graph_; - safe_ptr target_; - video_format_desc format_desc_; - - boost::timer produce_timer_; - boost::timer tick_timer_; - - std::map layers_; - std::map> transforms_; - - executor executor_; +struct stage::impl : public std::enable_shared_from_this +{ + spl::shared_ptr graph_; + spl::shared_ptr event_subject_; + std::map layers_; + std::map tweens_; + executor executor_; public: - implementation(const safe_ptr& graph, const safe_ptr& target, const video_format_desc& format_desc) - : graph_(graph) - , format_desc_(format_desc) - , target_(target) + impl(spl::shared_ptr graph) + : graph_(std::move(graph)) , executor_(L"stage") { - graph_->add_guide("tick-time", 0.5f); - graph_->set_color("tick-time", diagnostics::color(0.0f, 0.6f, 0.9f)); graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f)); } - - void spawn_token() - { - std::weak_ptr self = shared_from_this(); - executor_.begin_invoke([=]{tick(self);}); - } - - void tick(const std::weak_ptr& self) + + std::map> operator()(const struct video_format_desc& format_desc) { - try + return executor_.invoke([=]() -> std::map> { - produce_timer_.restart(); + boost::timer frame_timer; - std::map> frames; - - BOOST_FOREACH(auto& layer, layers_) - frames[layer.first] = basic_frame::empty(); + std::map> frames; + + try + { + std::vector indices; - tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map::value_type& layer) + BOOST_FOREACH(auto& layer, layers_) + { + frames[layer.first] = draw_frame::empty(); + indices.push_back(layer.first); + } + + // WORKAROUND: Compiler doesn't seem to like lambda. + tbb::parallel_for_each(indices.begin(), indices.end(), std::bind(&stage::impl::draw, this, std::placeholders::_1, std::ref(format_desc), std::ref(frames))); + } + catch(...) { - auto transform = transforms_[layer.first].fetch_and_tick(1); + layers_.clear(); + CASPAR_LOG_CURRENT_EXCEPTION(); + } + + graph_->set_value("produce-time", frame_timer.elapsed()*format_desc.fps*0.5); + *event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc.fps); - int flags = frame_producer::NO_FLAG; - if(format_desc_.field_mode != field_mode::progressive) - { - flags |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_FLAG : frame_producer::NO_FLAG; - flags |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_FLAG : frame_producer::NO_FLAG; - } + return frames; + }); + } - if(transform.is_key) - flags |= frame_producer::ALPHA_ONLY_FLAG; + void draw(int index, const video_format_desc& format_desc, std::map>& frames) + { + auto& layer = layers_[index]; + auto& tween = tweens_[index]; + auto transform = tween.fetch_and_tick(1); - auto frame = layer.second.receive(flags); - - auto frame1 = make_safe(frame); - frame1->get_frame_transform() = transform; - - if(format_desc_.field_mode != core::field_mode::progressive) - { - auto frame2 = make_safe(frame); - frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1); - frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode); - } - - frames[layer.first] = frame1; - }); - - graph_->update_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); - - std::shared_ptr ticket(nullptr, [self](void*) - { - auto self2 = self.lock(); - if(self2) - self2->executor_.begin_invoke([=]{tick(self);}); - }); + frame_producer::flags flags = frame_producer::flags::none; + if(format_desc.field_mode != field_mode::progressive) + { + flags |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none; + flags |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::flags::deinterlace : frame_producer::flags::none; + } - target_->send(std::make_pair(frames, ticket)); + if(transform.is_key) + flags |= frame_producer::flags::alpha_only; - graph_->update_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); - tick_timer_.restart(); + auto frame = layer.receive(flags, format_desc); + + frame = spl::make_shared(frame); + frame->get_frame_transform() = transform; + + if(format_desc.field_mode != core::field_mode::progressive) + { + auto frame2 = spl::make_shared(frame); + frame2->get_frame_transform() = tween.fetch_and_tick(1); + frame = core::draw_frame::interlace(frame, frame2, format_desc.field_mode); } - catch(...) + + frames[index] = frame; + } + + layer& get_layer(int index) + { + auto it = layers_.find(index); + if(it == std::end(layers_)) { - layers_.clear(); - CASPAR_LOG_CURRENT_EXCEPTION(); - } + it = layers_.insert(std::make_pair(index, layer(index))).first; + it->second.subscribe(event_subject_); + } + return it->second; } - void set_transform(int index, const frame_transform& transform, unsigned int mix_duration, const std::wstring& tween) + void apply_transforms(const std::vector>& transforms) { executor_.begin_invoke([=] { - auto src = transforms_[index].fetch(); - auto dst = transform; - transforms_[index] = tweened_transform(src, dst, mix_duration, tween); - }, high_priority); + BOOST_FOREACH(auto& transform, transforms) + { + auto src = tweens_[std::get<0>(transform)].fetch(); + auto dst = std::get<1>(transform)(src); + tweens_[std::get<0>(transform)] = tweened_transform(src, dst, std::get<2>(transform), std::get<3>(transform)); + } + }, task_priority::high_priority); } - - void apply_transform(int index, const std::function& transform, unsigned int mix_duration, const std::wstring& tween) + + void apply_transform(int index, const stage::transform_func_t& transform, unsigned int mix_duration, const tweener& tween) { executor_.begin_invoke([=] { - auto src = transforms_[index].fetch(); + auto src = tweens_[index].fetch(); auto dst = transform(src); - transforms_[index] = tweened_transform(src, dst, mix_duration, tween); - }, high_priority); + tweens_[index] = tweened_transform(src, dst, mix_duration, tween); + }, task_priority::high_priority); } void clear_transforms(int index) { executor_.begin_invoke([=] { - transforms_.erase(index); - }, high_priority); + tweens_.erase(index); + }, task_priority::high_priority); } void clear_transforms() { executor_.begin_invoke([=] { - transforms_.clear(); - }, high_priority); + tweens_.clear(); + }, task_priority::high_priority); } - void load(int index, const safe_ptr& producer, bool preview, int auto_play_delta) + void load(int index, const spl::shared_ptr& producer, const boost::optional& auto_play_delta) { executor_.begin_invoke([=] { - layers_[index].load(producer, preview, auto_play_delta); - }, high_priority); + get_layer(index).load(producer, auto_play_delta); + }, task_priority::high_priority); } void pause(int index) @@ -217,7 +189,7 @@ public: executor_.begin_invoke([=] { layers_[index].pause(); - }, high_priority); + }, task_priority::high_priority); } void play(int index) @@ -225,7 +197,7 @@ public: executor_.begin_invoke([=] { layers_[index].play(); - }, high_priority); + }, task_priority::high_priority); } void stop(int index) @@ -233,7 +205,7 @@ public: executor_.begin_invoke([=] { layers_[index].stop(); - }, high_priority); + }, task_priority::high_priority); } void clear(int index) @@ -241,7 +213,7 @@ public: executor_.begin_invoke([=] { layers_.erase(index); - }, high_priority); + }, task_priority::high_priority); } void clear() @@ -249,121 +221,133 @@ public: executor_.begin_invoke([=] { layers_.clear(); - }, high_priority); + }, task_priority::high_priority); } - - boost::unique_future call(int index, bool foreground, const std::wstring& param) - { - return std::move(*executor_.invoke([=] - { - return std::make_shared>(std::move(layers_[index].call(foreground, param))); - }, high_priority)); - } - - void swap_layers(const safe_ptr& other) + + void swap_layers(stage& other) { - if(other->impl_.get() == this) + auto other_impl = other.impl_; + + if(other_impl.get() == this) return; auto func = [=] { - std::swap(layers_, other->impl_->layers_); + auto layers = layers_ | boost::adaptors::map_values; + auto other_layers = other_impl->layers_ | boost::adaptors::map_values; + + BOOST_FOREACH(auto& layer, layers) + layer.unsubscribe(event_subject_); + + BOOST_FOREACH(auto& layer, other_layers) + layer.unsubscribe(event_subject_); + + std::swap(layers_, other_impl->layers_); + + BOOST_FOREACH(auto& layer, layers) + layer.subscribe(event_subject_); + + BOOST_FOREACH(auto& layer, other_layers) + layer.subscribe(event_subject_); }; executor_.begin_invoke([=] { - other->impl_->executor_.invoke(func, high_priority); - }, high_priority); + other_impl->executor_.invoke(func, task_priority::high_priority); + }, task_priority::high_priority); } - void swap_layer(int index, size_t other_index) + void swap_layer(int index, int other_index) { executor_.begin_invoke([=] { std::swap(layers_[index], layers_[other_index]); - }, high_priority); + }, task_priority::high_priority); } - void swap_layer(int index, size_t other_index, const safe_ptr& other) + void swap_layer(int index, int other_index, stage& other) { - if(other->impl_.get() == this) + auto other_impl = other.impl_; + + if(other_impl.get() == this) swap_layer(index, other_index); else { auto func = [=] { - std::swap(layers_[index], other->impl_->layers_[other_index]); + auto& my_layer = get_layer(index); + auto& other_layer = other_impl->get_layer(other_index); + + my_layer.unsubscribe(event_subject_); + other_layer.unsubscribe(other_impl->event_subject_); + + std::swap(my_layer, other_layer); + + my_layer.subscribe(event_subject_); + other_layer.subscribe(other_impl->event_subject_); }; executor_.begin_invoke([=] { - other->impl_->executor_.invoke(func, high_priority); - }, high_priority); + other_impl->executor_.invoke(func, task_priority::high_priority); + }, task_priority::high_priority); } } - boost::unique_future> foreground(int index) + boost::unique_future> foreground(int index) { return executor_.begin_invoke([=] { return layers_[index].foreground(); - }, high_priority); + }, task_priority::high_priority); } - boost::unique_future> background(int index) + boost::unique_future> background(int index) { return executor_.begin_invoke([=] { return layers_[index].background(); - }, high_priority); - } - - void set_video_format_desc(const video_format_desc& format_desc) - { - executor_.begin_invoke([=] - { - format_desc_ = format_desc; - }, high_priority); + }, task_priority::high_priority); } boost::unique_future info() { - return std::move(executor_.begin_invoke([&]() -> boost::property_tree::wptree + return executor_.begin_invoke([this]() -> boost::property_tree::wptree { boost::property_tree::wptree info; BOOST_FOREACH(auto& layer, layers_) info.add_child(L"layers.layer", layer.second.info()) .add(L"index", layer.first); return info; - }, high_priority)); + }, task_priority::high_priority); } boost::unique_future info(int index) { - return std::move(executor_.begin_invoke([&]() -> boost::property_tree::wptree + return executor_.begin_invoke([=] { return layers_[index].info(); - }, high_priority)); - } + }, task_priority::high_priority); + } }; -stage::stage(const safe_ptr& graph, const safe_ptr& target, const video_format_desc& format_desc) : impl_(new implementation(graph, target, format_desc)){} -void stage::set_frame_transform(int index, const core::frame_transform& transform, unsigned int mix_duration, const std::wstring& tween){impl_->set_transform(index, transform, mix_duration, tween);} -void stage::apply_frame_transform(int index, const std::function& transform, unsigned int mix_duration, const std::wstring& tween){impl_->apply_transform(index, transform, mix_duration, tween);} +stage::stage(spl::shared_ptr graph) : impl_(new impl(std::move(graph))){} +void stage::apply_transforms(const std::vector& transforms){impl_->apply_transforms(transforms);} +void stage::apply_transform(int index, const std::function& transform, unsigned int mix_duration, const tweener& tween){impl_->apply_transform(index, transform, mix_duration, tween);} void stage::clear_transforms(int index){impl_->clear_transforms(index);} void stage::clear_transforms(){impl_->clear_transforms();} -void stage::spawn_token(){impl_->spawn_token();} -void stage::load(int index, const safe_ptr& producer, bool preview, int auto_play_delta){impl_->load(index, producer, preview, auto_play_delta);} +void stage::load(int index, const spl::shared_ptr& producer, const boost::optional& auto_play_delta){impl_->load(index, producer, auto_play_delta);} void stage::pause(int index){impl_->pause(index);} void stage::play(int index){impl_->play(index);} void stage::stop(int index){impl_->stop(index);} void stage::clear(int index){impl_->clear(index);} void stage::clear(){impl_->clear();} -void stage::swap_layers(const safe_ptr& other){impl_->swap_layers(other);} -void stage::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);} -void stage::swap_layer(int index, size_t other_index, const safe_ptr& other){impl_->swap_layer(index, other_index, other);} -boost::unique_future> stage::foreground(int index) {return impl_->foreground(index);} -boost::unique_future> stage::background(int index) {return impl_->background(index);} -boost::unique_future stage::call(int index, bool foreground, const std::wstring& param){return impl_->call(index, foreground, param);} -void stage::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);} +void stage::swap_layers(stage& other){impl_->swap_layers(other);} +void stage::swap_layer(int index, int other_index){impl_->swap_layer(index, other_index);} +void stage::swap_layer(int index, int other_index, stage& other){impl_->swap_layer(index, other_index, other);} +boost::unique_future> stage::foreground(int index) {return impl_->foreground(index);} +boost::unique_future> stage::background(int index) {return impl_->background(index);} boost::unique_future stage::info() const{return impl_->info();} boost::unique_future stage::info(int index) const{return impl_->info(index);} +std::map> stage::operator()(const video_format_desc& format_desc){return (*impl_)(format_desc);} +void stage::subscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_->subscribe(o);} +void stage::unsubscribe(const monitor::observable::observer_ptr& o) {impl_->event_subject_->unsubscribe(o);} }} \ No newline at end of file