X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=core%2Fproducer%2Flayer.cpp;h=f7bf942d9705bba31a34f2185892e660cf19c156;hb=4b7ed0d71cd87485f4e30bcf3c34861f009bd39b;hp=d04c36dd1071e0e6514711fddd13cc4480ef673d;hpb=d7e2618675bf1936fa7324e07c04098ac8a3985d;p=casparcg diff --git a/core/producer/layer.cpp b/core/producer/layer.cpp index d04c36dd1..f7bf942d9 100644 --- a/core/producer/layer.cpp +++ b/core/producer/layer.cpp @@ -1,42 +1,95 @@ #include "../stdafx.h" #include "layer.h" +#include "frame_producer.h" -#include "../producer/frame_producer.h" +#include "../video_format.h" -#include "../format/video_format.h" +#include +#include +#include + +#include +#include +#include +#include + +#include namespace caspar { namespace core { -struct layer::implementation -{ - implementation() : foreground_(nullptr), background_(nullptr), last_frame_(nullptr) {} - - void load(const frame_producer_ptr& frame_producer, load_option::type option) +class frame_producer_remover +{ + executor executor_; + tbb::atomic count_; + + void do_remove(safe_ptr& producer) + { + auto name = producer->print(); + producer = frame_producer::empty(); + CASPAR_LOG(info) << name << L" Removed."; + } +public: + + frame_producer_remover() + { + executor_.start(); + count_ = 0; + } + + void remove(safe_ptr&& producer) { - if(frame_producer == nullptr) - BOOST_THROW_EXCEPTION(null_argument() << arg_name_info("frame_producer")); - + CASPAR_ASSERT(producer.unique()); + executor_.begin_invoke(std::bind(&frame_producer_remover::do_remove, this, std::move(producer))); + } +}; + +frame_producer_remover g_remover; + + +struct layer::implementation : boost::noncopyable +{ + mutable tbb::spin_mutex printer_mutex_; + printer parent_printer_; + int index_; + + safe_ptr foreground_; + safe_ptr background_; + safe_ptr last_frame_; + bool is_paused_; +public: + implementation(int index, const printer& parent_printer) + : parent_printer_(parent_printer) + , index_(index) + , foreground_(frame_producer::empty()) + , background_(frame_producer::empty()) + , last_frame_(draw_frame::empty()) + , is_paused_(false){} + + void load(const safe_ptr& frame_producer, bool play_on_load) + { background_ = frame_producer; - if(option == load_option::preview) - { - foreground_ = nullptr; - last_frame_ = frame_producer->render_frame(); - if(last_frame_ != nullptr) - last_frame_->audio_data().clear(); // No audio - } - else if(option == load_option::auto_play) - play(); + is_paused_ = false; + if(play_on_load) + play(); + } + + void preview(const safe_ptr& frame_producer) + { + load(frame_producer, true); + receive(); + pause(); } void play() { - if(background_ != nullptr) + if(!is_paused_) { background_->set_leading_producer(foreground_); - foreground_ = std::move(background_); + foreground_ = background_; + CASPAR_LOG(info) << foreground_->print() << L" Added."; + background_ = frame_producer::empty(); } - is_paused_ = false; } @@ -47,63 +100,97 @@ struct layer::implementation void stop() { - foreground_ = nullptr; - last_frame_ = nullptr; + pause(); + last_frame_ = draw_frame::empty(); + foreground_ = frame_producer::empty(); } void clear() - { - foreground_ = nullptr; - background_ = nullptr; - last_frame_ = nullptr; + { + foreground_ = frame_producer::empty(); + background_ = frame_producer::empty(); + last_frame_ = draw_frame::empty(); + is_paused_ = false; } - frame_ptr render_frame() + safe_ptr receive() { - if(!foreground_ || is_paused_) + if(is_paused_) + { + last_frame_->get_audio_transform().set_gain(0.0); return last_frame_; + } try { - last_frame_ = foreground_->render_frame(); - - if(last_frame_ == nullptr) + last_frame_ = foreground_->receive(); + if(last_frame_ == draw_frame::eof()) { - foreground_ = foreground_->get_following_producer(); - last_frame_ = render_frame(); + CASPAR_ASSERT(foreground_ != frame_producer::empty()); + + auto following = foreground_->get_following_producer(); + following->set_leading_producer(foreground_); + following->set_parent_printer(boost::bind(&implementation::print, this)); + g_remover.remove(std::move(foreground_)); + foreground_ = following; + CASPAR_LOG(info) << foreground_->print() << L" Added."; + + last_frame_ = receive(); } } catch(...) { + CASPAR_LOG(error) << print() << L" Unhandled Exception: "; CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(warning) << L"Removed " << (foreground_ ? foreground_->print() : L"frame_producer") << L" from layer."; - foreground_ = nullptr; - last_frame_ = nullptr; + stop(); } return last_frame_; - } + } - tbb::atomic is_paused_; - frame_ptr last_frame_; - frame_producer_ptr foreground_; - frame_producer_ptr background_; + std::wstring print() const + { + tbb::spin_mutex::scoped_lock lock(printer_mutex_); + return (parent_printer_ ? parent_printer_() + L"/" : L"") + L"layer[" + boost::lexical_cast(index_) + L"]"; + } }; -layer::layer() : impl_(new implementation()){} -layer::layer(layer&& other) : impl_(std::move(other.impl_)){other.impl_ = nullptr;} +layer::layer(int index, const printer& parent_printer) +{ + impl_ = new implementation(index, parent_printer); +} +layer::~layer() +{ + if(!impl_) + return; + + impl_->clear(); + delete impl_.fetch_and_store(nullptr); +} +layer::layer(layer&& other) +{ + impl_ = other.impl_.fetch_and_store(nullptr); +} layer& layer::operator=(layer&& other) { - impl_ = std::move(other.impl_); - other.impl_ = nullptr; + impl_ = other.impl_.fetch_and_store(nullptr); return *this; } -void layer::load(const frame_producer_ptr& frame_producer, load_option::type option){return impl_->load(frame_producer, option);} +void layer::swap(layer& other) +{ + impl_ = other.impl_.compare_and_swap(impl_, other.impl_); + tbb::spin_mutex::scoped_lock lock(other.impl_->printer_mutex_); + std::swap(impl_->index_, other.impl_->index_); + std::swap(impl_->parent_printer_, other.impl_->parent_printer_); +} +void layer::load(const safe_ptr& frame_producer, bool play_on_load){return impl_->load(frame_producer, play_on_load);} +void layer::preview(const safe_ptr& frame_producer){return impl_->preview(frame_producer);} void layer::play(){impl_->play();} void layer::pause(){impl_->pause();} void layer::stop(){impl_->stop();} void layer::clear(){impl_->clear();} -frame_ptr layer::render_frame() {return impl_->render_frame();} -frame_producer_ptr layer::foreground() const { return impl_->foreground_;} -frame_producer_ptr layer::background() const { return impl_->background_;} +safe_ptr layer::receive() {return impl_->receive();} +safe_ptr layer::foreground() const { return impl_->foreground_;} +safe_ptr layer::background() const { return impl_->background_;} +std::wstring layer::print() const { return impl_->print();} }} \ No newline at end of file