void tick(const std::weak_ptr<implementation>& self) { try { produce_timer_.restart(); std::map<int, safe_ptr<basic_frame>> frames; BOOST_FOREACH(auto& layer, layers_) frames[layer.first] = basic_frame::empty(); tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) { auto transform = transforms_[layer.first].fetch_and_tick(1); int hints = frame_producer::NO_HINT; if(format_desc_.field_mode != field_mode::progressive) { hints |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; } if(transform.is_key) hints |= frame_producer::ALPHA_HINT; auto frame = layer.second.receive(hints); auto frame1 = make_safe<core::basic_frame>(frame); frame1->get_frame_transform() = transform; if(format_desc_.field_mode != core::field_mode::progressive) { auto frame2 = make_safe<core::basic_frame>(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_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); std::shared_ptr<void> ticket(nullptr, [self](void*) { auto self2 = self.lock(); if(self2) self2->executor_.begin_invoke([=]{tick(self);}); }); target_->send(std::make_pair(frames, ticket)); graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); tick_timer_.restart(); } catch(...) { layers_.clear(); CASPAR_LOG_CURRENT_EXCEPTION(); } }
safe_ptr<basic_frame> compose(const safe_ptr<basic_frame>& dest_frame, const safe_ptr<basic_frame>& src_frame) { if(info_.type == transition::cut) return src_frame; const double delta1 = info_.tweener(current_frame_*2-1, 0.0, 1.0, info_.duration*2); const double delta2 = info_.tweener(current_frame_*2, 0.0, 1.0, info_.duration*2); const double dir = info_.direction == transition_direction::from_left ? 1.0 : -1.0; // For interlaced transitions. Seperate fields into seperate frames which are transitioned accordingly. auto s_frame1 = make_safe<basic_frame>(src_frame); auto s_frame2 = make_safe<basic_frame>(src_frame); s_frame1->get_frame_transform().volume = 0.0; s_frame2->get_frame_transform().volume = 1.0-delta2; auto d_frame1 = make_safe<basic_frame>(dest_frame); auto d_frame2 = make_safe<basic_frame>(dest_frame); d_frame1->get_frame_transform().volume = 0.0; d_frame2->get_frame_transform().volume = delta2; if(info_.type == transition::mix) { d_frame1->get_frame_transform().opacity = delta1; d_frame1->get_frame_transform().is_mix = true; d_frame2->get_frame_transform().opacity = delta2; d_frame2->get_frame_transform().is_mix = true; s_frame1->get_frame_transform().opacity = 1.0-delta1; s_frame1->get_frame_transform().is_mix = true; s_frame2->get_frame_transform().opacity = 1.0-delta2; s_frame2->get_frame_transform().is_mix = true; } if(info_.type == transition::slide) { d_frame1->get_frame_transform().fill_translation[0] = (-1.0+delta1)*dir; d_frame2->get_frame_transform().fill_translation[0] = (-1.0+delta2)*dir; } else if(info_.type == transition::push) { d_frame1->get_frame_transform().fill_translation[0] = (-1.0+delta1)*dir; d_frame2->get_frame_transform().fill_translation[0] = (-1.0+delta2)*dir; s_frame1->get_frame_transform().fill_translation[0] = (0.0+delta1)*dir; s_frame2->get_frame_transform().fill_translation[0] = (0.0+delta2)*dir; } else if(info_.type == transition::wipe) { d_frame1->get_frame_transform().clip_scale[0] = delta1; d_frame2->get_frame_transform().clip_scale[0] = delta2; } const auto s_frame = s_frame1->get_frame_transform() == s_frame2->get_frame_transform() ? s_frame2 : basic_frame::interlace(s_frame1, s_frame2, mode_); const auto d_frame = d_frame1->get_frame_transform() == d_frame2->get_frame_transform() ? d_frame2 : basic_frame::interlace(d_frame1, d_frame2, mode_); last_frame_ = basic_frame::combine(s_frame2, d_frame2); return basic_frame::combine(s_frame, d_frame); }
void tick(const std::weak_ptr<implementation>& self) { try { produce_timer_.restart(); std::map<int, safe_ptr<basic_frame>> frames; //fix g++ warning //std::map<int, std::shared_ptr<basic_frame>> frames; for(auto it = layers_.begin(); it != layers_.end(); ++it) frames[it->first] = make_safe<core::basic_frame>(basic_frame::empty()); tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, std::shared_ptr<layer>>::value_type& layer) { auto transform = transforms_[layer.first].fetch_and_tick(1); int hints = frame_producer::NO_HINT; if(format_desc_.field_mode != field_mode::progressive) { hints |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; } if(transform.is_key) hints |= frame_producer::ALPHA_HINT; auto frame = layer.second->receive(hints); auto layer_consumers_it = layer_consumers_.find(layer.first); if (layer_consumers_it != layer_consumers_.end()) { auto consumer_it = (*layer_consumers_it).second | boost::adaptors::map_values; tbb::parallel_for_each(consumer_it.begin(), consumer_it.end(), [&](decltype(*consumer_it.begin()) layer_consumer) { layer_consumer->send(frame); }); } auto frame1 = make_safe<core::basic_frame>(frame); frame1->get_frame_transform() = transform; if(format_desc_.field_mode != core::field_mode::progressive) { auto frame2 = make_safe<core::basic_frame>(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] = std::move(frame1); }); // Tick the transforms that does not have a corresponding layer. BOOST_FOREACH(auto& elem, transforms_) if (layers_.find(elem.first) == layers_.end()) elem.second.fetch_and_tick(format_desc_.field_mode != core::field_mode::progressive ? 2 : 1); graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); std::shared_ptr<void> ticket(nullptr, [=](void*) { auto self2 = self.lock(); if(self2) self2->executor_.begin_invoke([=]{tick(self);}); }); target_->send(std::make_pair(frames, ticket)); //comment out due to g++ warning fix */ graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); tick_timer_.restart(); } catch(...) { layers_.clear(); CASPAR_LOG_CURRENT_EXCEPTION(); } }