X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Ftransition%2Ftransition_producer.cpp;h=66c79b9ee3bfbc03d054b3ad951c5d39e034686e;hb=bb79328678a8758ed9227e6b436aae5f875fee57;hp=bdf15fd0619e731a5c0c32fb25a4ea34e24b30ce;hpb=822ad9fff5882a006c3de7448082da7d1a4bf489;p=casparcg diff --git a/core/producer/transition/transition_producer.cpp b/core/producer/transition/transition_producer.cpp index bdf15fd06..66c79b9ee 100644 --- a/core/producer/transition/transition_producer.cpp +++ b/core/producer/transition/transition_producer.cpp @@ -21,147 +21,152 @@ #include "transition_producer.h" -#include "../../format/video_format.h" -#include "../../processor/composite_frame.h" -#include "../../processor/transform_frame.h" -#include "../../processor/frame_processor_device.h" +#include -#include +#include +#include +#include + +#include namespace caspar { namespace core { -struct transition_producer::implementation : boost::noncopyable -{ - implementation(const safe_ptr& dest, const transition_info& info) : current_frame_(0), info_(info), - dest_producer_(dest), source_producer_(frame_producer::empty()) - {} +struct transition_producer : public frame_producer +{ + const video_mode::type mode_; + unsigned int current_frame_; + + const transition_info info_; + + safe_ptr dest_producer_; + safe_ptr source_producer_; + + safe_ptr last_frame_; - safe_ptr get_following_producer() const + explicit transition_producer(const video_mode::type& mode, const safe_ptr& dest, const transition_info& info) + : mode_(mode) + , current_frame_(0) + , info_(info) + , dest_producer_(dest) + , source_producer_(frame_producer::empty()) + , last_frame_(basic_frame::empty()){} + + // frame_producer + + virtual safe_ptr get_following_producer() const { return dest_producer_; } - void set_leading_producer(const safe_ptr& producer) + virtual void set_leading_producer(const safe_ptr& producer) { source_producer_ = producer; } - - safe_ptr receive() + + virtual safe_ptr receive(int hints) { if(current_frame_++ >= info_.duration) - return draw_frame::eof(); - - auto source = draw_frame::empty(); - auto dest = draw_frame::empty(); + return basic_frame::eof(); + + auto dest = basic_frame::empty(); + auto source = basic_frame::empty(); - tbb::parallel_invoke - ( - [&]{dest = receive(dest_producer_);}, - [&]{source = receive(source_producer_);} - ); + tbb::parallel_invoke( + [&] + { + dest = receive_and_follow(dest_producer_, hints); + if(dest == core::basic_frame::late()) + dest = dest_producer_->last_frame(); + }, + [&] + { + source = receive_and_follow(source_producer_, hints); + if(source == core::basic_frame::late()) + source = source_producer_->last_frame(); + }); - return compose(dest, source); + return last_frame_ = compose(dest, source); } - safe_ptr receive(safe_ptr& producer) + virtual safe_ptr last_frame() const { - if(producer == frame_producer::empty()) - return draw_frame::eof(); + return disable_audio(last_frame_); + } - auto frame = draw_frame::eof(); - try - { - frame = producer->receive(); - } - catch(...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(warning) << "Failed to receive frame. Removed producer from transition."; - } + virtual int64_t nb_frames() const + { + return get_following_producer()->nb_frames(); + } - if(frame == draw_frame::eof()) - { - try - { - auto following = producer->get_following_producer(); - following->initialize(safe_ptr(frame_processor_)); - following->set_leading_producer(producer); - producer = std::move(following); - } - catch(...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(warning) << "Failed to initialize following producer."; - } - - return receive(producer); - } - return frame; + virtual std::wstring print() const + { + return L"transition[" + source_producer_->print() + L"|" + dest_producer_->print() + L"]"; } - - safe_ptr compose(const safe_ptr& dest_frame, const safe_ptr& src_frame) + + // transition_producer + + safe_ptr compose(const safe_ptr& dest_frame, const safe_ptr& src_frame) { - if(dest_frame == draw_frame::eof() && src_frame == draw_frame::eof()) - return draw_frame::eof(); - if(info_.type == transition::cut) - return src_frame != draw_frame::eof() ? src_frame : draw_frame::empty(); + return src_frame; - double alpha = static_cast(current_frame_)/static_cast(info_.duration); + 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); - auto my_src_frame = transform_frame(src_frame); - auto my_dest_frame = transform_frame(dest_frame); + 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(src_frame); + auto s_frame2 = make_safe(src_frame); - my_src_frame.audio_volume(1.0-alpha); - my_dest_frame.audio_volume(alpha); + s_frame1->get_audio_transform().set_has_audio(false); + s_frame2->get_audio_transform().set_gain(1.0-delta2); - double dir = info_.direction == transition_direction::from_left ? 1.0 : -1.0; + auto d_frame1 = make_safe(dest_frame); + auto d_frame2 = make_safe(dest_frame); + d_frame1->get_audio_transform().set_has_audio(false); + d_frame2->get_audio_transform().set_gain(delta2); + if(info_.type == transition::mix) - my_dest_frame.alpha(alpha); - else if(info_.type == transition::slide) - my_dest_frame.translate((-1.0+alpha)*dir, 0.0); - else if(info_.type == transition::push) { - my_dest_frame.translate((-1.0+alpha)*dir, 0.0); - my_src_frame.translate((0.0+alpha)*dir, 0.0); + d_frame1->get_image_transform().set_opacity(delta1); + d_frame2->get_image_transform().set_opacity(delta2); + + //s_frame1->get_image_transform().set_opacity(1.0-delta1); + //s_frame2->get_image_transform().set_opacity(1.0-delta2); } - else if(info_.type == transition::wipe) + else if(info_.type == transition::slide) { - my_dest_frame.translate((-1.0+alpha)*dir, 0.0); - my_dest_frame.texcoord((-1.0+alpha)*dir, 0.0, 0.0-(1.0-alpha)*dir, 0.0); + d_frame1->get_image_transform().set_fill_translation((-1.0+delta1)*dir, 0.0); + d_frame2->get_image_transform().set_fill_translation((-1.0+delta2)*dir, 0.0); } + else if(info_.type == transition::push) + { + d_frame1->get_image_transform().set_fill_translation((-1.0+delta1)*dir, 0.0); + d_frame2->get_image_transform().set_fill_translation((-1.0+delta2)*dir, 0.0); - return composite_frame(std::move(my_src_frame), std::move(my_dest_frame)); - } + s_frame1->get_image_transform().set_fill_translation((0.0+delta1)*dir, 0.0); + s_frame2->get_image_transform().set_fill_translation((0.0+delta2)*dir, 0.0); + } + else if(info_.type == transition::wipe) + { + d_frame1->get_image_transform().set_clip_scale(delta1, 1.0); + d_frame2->get_image_transform().set_clip_scale(delta2, 1.0); + } + + const auto s_frame = s_frame1->get_image_transform() == s_frame2->get_image_transform() ? s_frame2 : basic_frame::interlace(s_frame1, s_frame2, mode_); + const auto d_frame = d_frame1->get_image_transform() == d_frame2->get_image_transform() ? d_frame2 : basic_frame::interlace(d_frame1, d_frame2, mode_); - void initialize(const safe_ptr& frame_processor) - { - dest_producer_->initialize(frame_processor); - frame_processor_ = frame_processor; - } - - std::wstring print() const - { - return L"transition[" + (source_producer_->print()) + L" -> " + (dest_producer_->print()) + L"]"; + return basic_frame::combine(s_frame, d_frame); } - - safe_ptr source_producer_; - safe_ptr dest_producer_; - - unsigned short current_frame_; - - const transition_info info_; - std::shared_ptr frame_processor_; }; -transition_producer::transition_producer(transition_producer&& other) : impl_(std::move(other.impl_)){} -transition_producer::transition_producer(const safe_ptr& dest, const transition_info& info) : impl_(new implementation(dest, info)){} -safe_ptr transition_producer::receive(){return impl_->receive();} -safe_ptr transition_producer::get_following_producer() const{return impl_->get_following_producer();} -void transition_producer::set_leading_producer(const safe_ptr& producer) { impl_->set_leading_producer(producer); } -void transition_producer::initialize(const safe_ptr& frame_processor) { impl_->initialize(frame_processor);} -std::wstring transition_producer::print() const { return impl_->print();} +safe_ptr create_transition_producer(const video_mode::type& mode, const safe_ptr& destination, const transition_info& info) +{ + return make_safe(mode, destination, info); +} }}