X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Ftransition%2Ftransition_producer.cpp;h=6fe58ec62ebc9578d7e7ee0c8fd79a0165b8efee;hb=a5d62563b4fce4e471dd56a6178430f6471fad94;hp=0dcc110f336125d09149dd4f90462f90c24e5c89;hpb=e3c3c294009fa769f2e19950e528d509b1ea286b;p=casparcg diff --git a/core/producer/transition/transition_producer.cpp b/core/producer/transition/transition_producer.cpp index 0dcc110f3..6fe58ec62 100644 --- a/core/producer/transition/transition_producer.cpp +++ b/core/producer/transition/transition_producer.cpp @@ -21,146 +21,154 @@ #include "transition_producer.h" -#include "../../frame/frame_format.h" -#include "../../frame/gpu_frame.h" -#include "../../frame/gpu_composite_frame.h" -#include "../../frame/frame_factory.h" +#include -#include "../../../common/utility/memory.h" -#include "../../renderer/render_device.h" +#include +#include +#include -#include +#include namespace caspar { namespace core { -struct transition_producer::implementation : boost::noncopyable -{ - implementation(const frame_producer_ptr& dest, const transition_info& info, const frame_format_desc& format_desc) - : current_frame_(0), info_(info), format_desc_(format_desc), dest_(dest) - { - if(!dest) - BOOST_THROW_EXCEPTION(null_argument() << arg_name_info("dest")); - } +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_; - frame_producer_ptr get_following_producer() const - { - return dest_; - } + 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()){} - void set_leading_producer(const frame_producer_ptr& producer) + // frame_producer + + virtual safe_ptr get_following_producer() const { - source_ = producer; + return dest_producer_; } - - gpu_frame_ptr get_frame() + + virtual void set_leading_producer(const safe_ptr& producer) { - return ++current_frame_ >= info_.duration ? nullptr : compose(get_producer_frame(dest_), get_producer_frame(source_)); + source_producer_ = producer; } - gpu_frame_ptr get_producer_frame(frame_producer_ptr& producer) + virtual safe_ptr receive(int hints) { - if(producer == nullptr) - { - auto frame = factory_->create_frame(format_desc_); - common::clear(frame->data(), frame->size()); - return frame; - } + if(++current_frame_ >= info_.duration) + return basic_frame::eof(); + + auto dest = basic_frame::empty(); + auto source = basic_frame::empty(); - gpu_frame_ptr frame; - try + tbb::parallel_invoke( + [&] { - frame = producer->get_frame(); - } - catch(...) + dest = receive_and_follow(dest_producer_, hints); + if(dest == core::basic_frame::late()) + dest = dest_producer_->last_frame(); + }, + [&] { - CASPAR_LOG_CURRENT_EXCEPTION(); - producer = nullptr; - CASPAR_LOG(warning) << "Removed renderer from transition."; - } + source = receive_and_follow(source_producer_, hints); + if(source == core::basic_frame::late()) + source = source_producer_->last_frame(); + }); - if(frame == nullptr && producer != nullptr && producer->get_following_producer() != nullptr) - { - auto following = producer->get_following_producer(); - following->initialize(factory_); - following->set_leading_producer(producer); - producer = following; - return get_producer_frame(producer); - } - return frame; + return compose(dest, source); + } + + virtual safe_ptr last_frame() const + { + return disable_audio(last_frame_); + } + + virtual int64_t nb_frames() const + { + return get_following_producer()->nb_frames(); } - - gpu_frame_ptr compose(const gpu_frame_ptr& dest_frame, const gpu_frame_ptr& src_frame) - { - if(!src_frame) - return dest_frame; - if(info_.type == transition_type::cut || !dest_frame) + virtual std::wstring print() const + { + return L"transition[" + source_producer_->print() + L"|" + dest_producer_->print() + L"]"; + } + + // transition_producer + + safe_ptr compose(const safe_ptr& dest_frame, const safe_ptr& 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; - int volume = static_cast(static_cast(current_frame_)/static_cast(info_.duration)*256.0); - - for(size_t n = 0; n < dest_frame->audio_data().size(); ++n) - dest_frame->audio_data()[n] = static_cast((static_cast(dest_frame->audio_data()[n])*volume)>>8); + // 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); - for(size_t n = 0; n < src_frame->audio_data().size(); ++n) - src_frame->audio_data()[n] = static_cast((static_cast(src_frame->audio_data()[n])*(256-volume))>>8); - - float alpha = static_cast(current_frame_)/static_cast(info_.duration); - auto composite = std::make_shared(format_desc_.width, format_desc_.height); - composite->add(src_frame); - composite->add(dest_frame); - if(info_.type == transition_type::mix) + s_frame1->get_audio_transform().set_has_audio(false); + s_frame2->get_audio_transform().set_gain(1.0-delta2); + + 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) + //{ + // 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); + //} + if(info_.type == transition::slide) { - src_frame->alpha(1.0f-alpha); - dest_frame->alpha(alpha); + 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_type::slide) + else if(info_.type == transition::push) { - if(info_.direction == transition_direction::from_left) - dest_frame->translate(-1.0f+alpha, 0.0f); - else if(info_.direction == transition_direction::from_right) - dest_frame->translate(1.0f-alpha, 0.0f); + 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); + + 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_type::push) + else if(info_.type == transition::wipe) { - if(info_.direction == transition_direction::from_left) - { - dest_frame->translate(-1.0f+alpha, 0.0f); - src_frame->translate(0.0f+alpha, 0.0f); - } - else if(info_.direction == transition_direction::from_right) - { - dest_frame->translate(1.0f-alpha, 0.0f); - src_frame->translate(0.0f-alpha, 0.0f); - } + d_frame1->get_image_transform().set_clip_scale(delta1, 1.0); + d_frame2->get_image_transform().set_clip_scale(delta2, 1.0); } - return composite; - } + + 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 frame_factory_ptr& factory) - { - dest_->initialize(factory); - factory_ = factory; - } + last_frame_ = basic_frame::combine(s_frame2, d_frame2); - const frame_format_desc format_desc_; - - frame_producer_ptr source_; - frame_producer_ptr dest_; - - unsigned short current_frame_; - - const transition_info info_; - frame_factory_ptr factory_; + return basic_frame::combine(s_frame, d_frame); + } }; -transition_producer::transition_producer(const frame_producer_ptr& dest, const transition_info& info, const frame_format_desc& format_desc) - : impl_(new implementation(dest, info, format_desc)){} -gpu_frame_ptr transition_producer::get_frame(){return impl_->get_frame();} -frame_producer_ptr transition_producer::get_following_producer() const{return impl_->get_following_producer();} -void transition_producer::set_leading_producer(const frame_producer_ptr& producer) { impl_->set_leading_producer(producer); } -const frame_format_desc& transition_producer::get_frame_format_desc() const { return impl_->format_desc_; } -void transition_producer::initialize(const frame_factory_ptr& factory) { impl_->initialize(factory);} +safe_ptr create_transition_producer(const video_mode::type& mode, const safe_ptr& destination, const transition_info& info) +{ + return make_safe(mode, destination, info); +} }}