X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Fframe_producer.cpp;h=de25a488e792be9a12a95192375557188a4634e4;hb=06bdd05d8ec7da072de717d5e1fcb462a1d8ee56;hp=bfe9223fb866ca91272a58b2ac3e46c991efd6c2;hpb=c3a76b811579dd3a52227e170903da821c04ae9e;p=casparcg diff --git a/core/producer/frame_producer.cpp b/core/producer/frame_producer.cpp index bfe9223fb..de25a488e 100644 --- a/core/producer/frame_producer.cpp +++ b/core/producer/frame_producer.cpp @@ -22,12 +22,12 @@ #include "../StdAfx.h" #include "frame_producer.h" +#include "cg_proxy.h" #include "../frame/draw_frame.h" #include "../frame/frame_transform.h" #include "color/color_producer.h" -#include "draw/freehand_producer.h" #include "separated/separated_producer.h" #include "variable.h" @@ -40,17 +40,46 @@ #include namespace caspar { namespace core { - -std::vector g_factories; -std::vector g_thumbnail_factories; +struct frame_producer_registry::impl +{ + std::vector producer_factories; + std::vector thumbnail_producers; + spl::shared_ptr help_repo; + + impl(spl::shared_ptr help_repo) + : help_repo(std::move(help_repo)) + { + } +}; -void register_producer_factory(const producer_factory_t& factory) +frame_producer_registry::frame_producer_registry(spl::shared_ptr help_repo) + : impl_(new impl(std::move(help_repo))) { - g_factories.push_back(factory); } -void register_thumbnail_producer_factory(const producer_factory_t& factory) + +void frame_producer_registry::register_producer_factory(std::wstring name, const producer_factory_t& factory, const help_item_describer& describer) +{ + impl_->producer_factories.push_back(factory); + impl_->help_repo->register_item({ L"producer" }, std::move(name), describer); +} + +void frame_producer_registry::register_thumbnail_producer(const thumbnail_producer_t& thumbnail_producer) +{ + impl_->thumbnail_producers.push_back(thumbnail_producer); +} + +frame_producer_dependencies::frame_producer_dependencies( + const spl::shared_ptr& frame_factory, + const std::vector>& channels, + const video_format_desc& format_desc, + const spl::shared_ptr producer_registry, + const spl::shared_ptr cg_registry) + : frame_factory(frame_factory) + , channels(channels) + , format_desc(format_desc) + , producer_registry(producer_registry) + , cg_registry(cg_registry) { - g_thumbnail_factories.push_back(factory); } constraints::constraints(double width, double height) @@ -76,7 +105,7 @@ struct frame_producer_base::impl frame_number_ = 0; paused_ = false; } - + draw_frame receive() { if(paused_) @@ -100,10 +129,6 @@ struct frame_producer_base::impl { return draw_frame::still(last_frame_); } - draw_frame create_thumbnail_frame() - { - return draw_frame::empty(); - } }; frame_producer_base::frame_producer_base() : impl_(new impl(*this)) @@ -124,12 +149,8 @@ draw_frame frame_producer_base::last_frame() { return impl_->last_frame(); } -draw_frame frame_producer_base::create_thumbnail_frame() -{ - return impl_->create_thumbnail_frame(); -} -boost::unique_future frame_producer_base::call(const std::vector&) +std::future frame_producer_base::call(const std::vector&) { CASPAR_THROW_EXCEPTION(not_supported()); } @@ -146,7 +167,7 @@ uint32_t frame_producer_base::frame_number() const variable& frame_producer_base::get_variable(const std::wstring& name) { - CASPAR_THROW_EXCEPTION(caspar_exception() + CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"No variable called " + name + L" found in " + print())); } @@ -157,7 +178,7 @@ const std::vector& frame_producer_base::get_variables() const return empty; } -const spl::shared_ptr& frame_producer::empty() +const spl::shared_ptr& frame_producer::empty() { class empty_frame_producer : public frame_producer { @@ -167,16 +188,15 @@ const spl::shared_ptr& frame_producer::empty() void paused(bool value) override{} uint32_t nb_frames() const override {return 0;} std::wstring print() const override { return L"empty";} - monitor::source& monitor_output() override {static monitor::subject monitor_subject(""); return monitor_subject;} + monitor::subject& monitor_output() override {static monitor::subject monitor_subject(""); return monitor_subject;} std::wstring name() const override {return L"empty";} uint32_t frame_number() const override {return 0;} - boost::unique_future call(const std::vector& params) override{CASPAR_THROW_EXCEPTION(not_supported());} - variable& get_variable(const std::wstring& name) override { CASPAR_THROW_EXCEPTION(not_supported()); } + std::future call(const std::vector& params) override{CASPAR_THROW_EXCEPTION(not_implemented());} + variable& get_variable(const std::wstring& name) override { CASPAR_THROW_EXCEPTION(not_implemented()); } const std::vector& get_variables() const override { static std::vector empty; return empty; } draw_frame last_frame() {return draw_frame::empty();} - draw_frame create_thumbnail_frame() {return draw_frame::empty();} constraints& pixel_constraints() override { static constraints c; return c; } - + boost::property_tree::wptree info() const override { boost::property_tree::wptree info; @@ -187,41 +207,71 @@ const spl::shared_ptr& frame_producer::empty() static spl::shared_ptr producer = spl::make_shared(); return producer; -} +} + +std::shared_ptr& producer_destroyer() +{ + static auto destroyer = [] + { + auto result = std::make_shared(L"Producer destroyer"); + result->set_capacity(std::numeric_limits::max()); + return result; + }();; + + return destroyer; +} + +tbb::atomic& destroy_producers_in_separate_thread() +{ + static tbb::atomic state; + + return state; +} + +void destroy_producers_synchronously() +{ + destroy_producers_in_separate_thread() = false; + // Join destroyer, executing rest of producers in queue synchronously. + producer_destroyer().reset(); +} class destroy_producer_proxy : public frame_producer -{ +{ std::shared_ptr producer_; public: - destroy_producer_proxy(spl::shared_ptr&& producer) + destroy_producer_proxy(spl::shared_ptr&& producer) : producer_(std::move(producer)) { + destroy_producers_in_separate_thread() = true; } virtual ~destroy_producer_proxy() - { - static tbb::atomic counter = tbb::atomic(); - - if(producer_ == core::frame_producer::empty()) + { + if(producer_ == core::frame_producer::empty() || !destroy_producers_in_separate_thread()) + return; + + auto destroyer = producer_destroyer(); + + if (!destroyer) return; - ++counter; - CASPAR_VERIFY(counter < 8); - + CASPAR_VERIFY(destroyer->size() < 8); + auto producer = new spl::shared_ptr(std::move(producer_)); - boost::thread([=] + + destroyer->begin_invoke([=] { std::unique_ptr> pointer_guard(producer); auto str = (*producer)->print(); try { - if(!producer->unique()) - CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count(); + if (!producer->unique()) + CASPAR_LOG(debug) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count(); else - CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread."; + CASPAR_LOG(debug) << str << L" Destroying on asynchronous destruction thread."; } catch(...){} - + try { pointer_guard.reset(); @@ -231,27 +281,24 @@ public: { CASPAR_LOG_CURRENT_EXCEPTION(); } - - --counter; - }).detach(); + }); } - - draw_frame receive() override {return producer_->receive();} + + draw_frame receive() override {return producer_->receive();} std::wstring print() const override {return producer_->print();} void paused(bool value) override {producer_->paused(value);} std::wstring name() const override {return producer_->name();} uint32_t frame_number() const override {return producer_->frame_number();} boost::property_tree::wptree info() const override {return producer_->info();} - boost::unique_future call(const std::vector& params) override {return producer_->call(params);} + std::future call(const std::vector& params) override {return producer_->call(params);} variable& get_variable(const std::wstring& name) override {return producer_->get_variable(name);} const std::vector& get_variables() const override {return producer_->get_variables();} void leading_producer(const spl::shared_ptr& producer) override {return producer_->leading_producer(producer);} uint32_t nb_frames() const override {return producer_->nb_frames();} - class draw_frame last_frame() {return producer_->last_frame();} - draw_frame create_thumbnail_frame() {return producer_->create_thumbnail_frame();} - monitor::source& monitor_output() override {return producer_->monitor_output();} - bool collides(double x, double y) {return producer_->collides(x, y);} - void on_interaction(const interaction_event::ptr& event) {return producer_->on_interaction(event);} + draw_frame last_frame() {return producer_->last_frame();} + monitor::subject& monitor_output() override {return producer_->monitor_output();} + bool collides(double x, double y) const override {return producer_->collides(x, y);} + void on_interaction(const interaction_event::ptr& event) override {return producer_->on_interaction(event);} constraints& pixel_constraints() override {return producer_->pixel_constraints();} }; @@ -260,17 +307,21 @@ spl::shared_ptr create_destroy_proxy(spl::shared_ptr(std::move(producer)); } -spl::shared_ptr do_create_producer(const spl::shared_ptr& my_frame_factory, const video_format_desc& format_desc, const std::vector& params, const std::vector& factories, bool throw_on_fail = false) +spl::shared_ptr do_create_producer(const frame_producer_dependencies& dependencies, const std::vector& params, const std::vector& factories, bool throw_on_fail = false) { if(params.empty()) - CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info("")); - + CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("params cannot be empty")); + auto producer = frame_producer::empty(); std::any_of(factories.begin(), factories.end(), [&](const producer_factory_t& factory) -> bool { try { - producer = factory(my_frame_factory, format_desc, params); + producer = factory(dependencies, params); + } + catch (user_error&) + { + throw; } catch(...) { @@ -283,75 +334,80 @@ spl::shared_ptr do_create_producer(const spl::shared_ptr create_thumbnail_producer(const spl::shared_ptr& my_frame_factory, const video_format_desc& format_desc, const std::wstring& media_file) +draw_frame do_create_thumbnail_frame( + const frame_producer_dependencies& dependencies, + const std::wstring& media_file, + const std::vector& thumbnail_producers) { - std::vector params; - params.push_back(media_file); - - auto producer = do_create_producer(my_frame_factory, format_desc, params, g_thumbnail_factories, true); - auto key_producer = frame_producer::empty(); - - try // to find a key file. - { - auto params_copy = params; - if (params_copy.size() > 0) + for (auto& thumbnail_producer : thumbnail_producers) { - params_copy[0] += L"_A"; - key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_thumbnail_factories, true); - if (key_producer == frame_producer::empty()) - { - params_copy[0] += L"LPHA"; - key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_thumbnail_factories, true); - } + auto frame = thumbnail_producer(dependencies, media_file); + + if (frame != draw_frame::empty()) + return frame; } - } - catch(...){} - if (producer != frame_producer::empty() && key_producer != frame_producer::empty()) - return create_separated_producer(producer, key_producer); - - return producer; + return draw_frame::empty(); +} + +draw_frame frame_producer_registry::create_thumbnail(const frame_producer_dependencies& dependencies, const std::wstring& media_file) const +{ + auto& thumbnail_producers = impl_->thumbnail_producers; + std::vector params; + params.push_back(media_file); + + auto fill_frame = do_create_thumbnail_frame(dependencies, media_file, thumbnail_producers); + auto key_frame = do_create_thumbnail_frame(dependencies, media_file + L"_A", thumbnail_producers); + + if (key_frame == draw_frame::empty()) + key_frame = do_create_thumbnail_frame(dependencies, media_file + L"_ALPHA", thumbnail_producers); + + if (fill_frame != draw_frame::empty() && key_frame != draw_frame::empty()) + return draw_frame::mask(fill_frame, key_frame); + + return fill_frame; } -spl::shared_ptr create_producer(const spl::shared_ptr& my_frame_factory, const video_format_desc& format_desc, const std::vector& params) -{ - auto producer = do_create_producer(my_frame_factory, format_desc, params, g_factories); +spl::shared_ptr frame_producer_registry::create_producer(const frame_producer_dependencies& dependencies, const std::vector& params) const +{ + auto& producer_factories = impl_->producer_factories; + auto producer = do_create_producer(dependencies, params, producer_factories); auto key_producer = frame_producer::empty(); - - try // to find a key file. + + if (!params.empty() && !boost::contains(params.at(0), L"://")) { - auto params_copy = params; - if(params_copy.size() > 0) + try // to find a key file. { - params_copy[0] += L"_A"; - key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_factories); - if(key_producer == frame_producer::empty()) + auto params_copy = params; + if (params_copy.size() > 0) { - params_copy[0] += L"LPHA"; - key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_factories); + params_copy[0] += L"_A"; + key_producer = do_create_producer(dependencies, params_copy, producer_factories); + if (key_producer == frame_producer::empty()) + { + params_copy[0] += L"LPHA"; + key_producer = do_create_producer(dependencies, params_copy, producer_factories); + } } } + catch (...) {} } - catch(...){} if(producer != frame_producer::empty() && key_producer != frame_producer::empty()) return create_separated_producer(producer, key_producer); - + if(producer == frame_producer::empty()) { std::wstring str; - BOOST_FOREACH(auto& param, params) + for (auto& param : params) str += param + L" "; CASPAR_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.") << arg_value_info(u8(str))); } @@ -360,13 +416,12 @@ spl::shared_ptr create_producer(const spl::shared_ptr create_producer(const spl::shared_ptr& factory, const video_format_desc& format_desc, const std::wstring& params) +spl::shared_ptr frame_producer_registry::create_producer(const frame_producer_dependencies& dependencies, const std::wstring& params) const { std::wstringstream iss(params); std::vector tokens; typedef std::istream_iterator > iterator; std::copy(iterator(iss), iterator(), std::back_inserter(tokens)); - return create_producer(factory, format_desc, tokens); + return create_producer(dependencies, tokens); } - -}} \ No newline at end of file +}}