X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=shell%2Fserver.cpp;h=86b1736157d75f0902e11f410d723caec961e5a4;hb=d0c0b48630570ccd60d5c2454561864a654e04df;hp=87000acb8a6baa67f8f3ccdf4a2f458a72a29d6f;hpb=695a2cc6ecea40006d1f661edaeeeaa415ab7d53;p=casparcg diff --git a/shell/server.cpp b/shell/server.cpp index 87000acb8..86b173615 100644 --- a/shell/server.cpp +++ b/shell/server.cpp @@ -31,24 +31,31 @@ #include #include +#include #include #include #include #include +#include +#include +#include #include #include #include #include +#include #include #include -#include +#include #include #include #include #include +#include #include +#include #include #include @@ -58,23 +65,49 @@ #include #include #include -#include #include #include +#include #include #include #include +#include + +#include namespace caspar { using namespace core; using namespace protocol; +std::shared_ptr create_running_io_service() +{ + auto service = std::make_shared(); + // To keep the io_service::run() running although no pending async + // operations are posted. + auto work = std::make_shared(*service); + auto thread = std::make_shared([service] + { + win32_exception::ensure_handler_installed_for_thread("asio-thread"); + + service->run(); + }); + + return std::shared_ptr( + service.get(), + [service, work, thread] (void*) mutable + { + work.reset(); + service->stop(); + thread->join(); + }); +} + struct server::implementation : boost::noncopyable { - protocol::asio::io_service_manager io_service_manager_; - core::monitor::subject monitor_subject_; + std::shared_ptr io_service_; + safe_ptr monitor_subject_; boost::promise& shutdown_server_now_; safe_ptr ogl_; std::vector> async_servers_; @@ -82,16 +115,25 @@ struct server::implementation : boost::noncopyable osc::client osc_client_; std::vector> predefined_osc_subscriptions_; std::vector> channels_; + safe_ptr media_info_repo_; + boost::thread initial_media_info_thread_; + tbb::atomic running_; std::shared_ptr thumbnail_generator_; implementation(boost::promise& shutdown_server_now) - : shutdown_server_now_(shutdown_server_now) + : io_service_(create_running_io_service()) + , shutdown_server_now_(shutdown_server_now) , ogl_(ogl_device::create()) - , osc_client_(io_service_manager_.service(), monitor_subject_) + , osc_client_(io_service_) + , media_info_repo_(create_in_memory_media_info_repository()) { + running_ = true; setup_audio(env::properties()); + + html::init(); + CASPAR_LOG(info) << L"Initialized html module."; - ffmpeg::init(); + ffmpeg::init(media_info_repo_); CASPAR_LOG(info) << L"Initialized ffmpeg module."; bluefish::init(); @@ -99,19 +141,22 @@ struct server::implementation : boost::noncopyable decklink::init(); CASPAR_LOG(info) << L"Initialized decklink module."; - - oal::init(); + + oal::init(); CASPAR_LOG(info) << L"Initialized oal module."; + newtek::init(); + CASPAR_LOG(info) << L"Initialized newtek module."; + ogl::init(); CASPAR_LOG(info) << L"Initialized ogl module."; - image::init(); - CASPAR_LOG(info) << L"Initialized image module."; - flash::init(); CASPAR_LOG(info) << L"Initialized flash module."; + image::init(); + CASPAR_LOG(info) << L"Initialized image module."; + setup_channels(env::properties()); CASPAR_LOG(info) << L"Initialized channels."; @@ -122,15 +167,23 @@ struct server::implementation : boost::noncopyable setup_osc(env::properties()); CASPAR_LOG(info) << L"Initialized osc."; + + start_initial_media_info_scan(); + CASPAR_LOG(info) << L"Started initial media information retrieval."; } ~implementation() - { - ffmpeg::uninit(); - + { + running_ = false; + initial_media_info_thread_.join(); + thumbnail_generator_.reset(); primary_amcp_server_.reset(); async_servers_.clear(); + destroy_producers_synchronously(); channels_.clear(); + + html::uninit(); + ffmpeg::uninit(); } void setup_audio(const boost::property_tree::wptree& pt) @@ -165,7 +218,9 @@ struct server::implementation : boost::noncopyable channels_.push_back(make_safe(channels_.size()+1, format_desc, ogl_, audio_channel_layout)); - channels_.back()->monitor_output().link_target(&monitor_subject_); + channels_.back()->monitor_output().attach_parent(monitor_subject_); + channels_.back()->mixer()->set_straight_alpha_output( + xml_channel.second.get(L"straight-alpha-output", false)); create_consumers( xml_channel.second.get_child(L"consumers"), @@ -177,7 +232,10 @@ struct server::implementation : boost::noncopyable // Dummy diagnostics channel if(env::properties().get(L"configuration.channel-grid", false)) + { channels_.push_back(make_safe(channels_.size()+1, core::video_format_desc::get(core::video_format::x576p2500), ogl_, default_channel_layout_repository().get_by_name(L"STEREO"))); + channels_.back()->monitor_output().attach_parent(monitor_subject_); + } } template @@ -208,6 +266,10 @@ struct server::implementation : boost::noncopyable on_consumer(bluefish::create_consumer(xml_consumer.second)); else if (name == L"decklink") on_consumer(decklink::create_consumer(xml_consumer.second)); + else if (name == L"newtek-ivga") + on_consumer(newtek::create_ivga_consumer(xml_consumer.second)); + else if (name == L"blocking-decklink") + on_consumer(decklink::create_blocking_consumer(xml_consumer.second)); else if (name == L"file" || name == L"stream") on_consumer(ffmpeg::create_consumer(xml_consumer.second)); else if (name == L"system-audio") @@ -256,6 +318,8 @@ struct server::implementation : boost::noncopyable { using boost::property_tree::wptree; using namespace boost::asio::ip; + + monitor_subject_->attach_parent(osc_client_.sink()); auto default_port = pt.get(L"configuration.osc.default-port", 6250); @@ -298,7 +362,8 @@ struct server::implementation : boost::noncopyable auto scan_interval_millis = pt.get(L"configuration.thumbnails.scan-interval-millis", 5000); - polling_filesystem_monitor_factory monitor_factory(scan_interval_millis); + polling_filesystem_monitor_factory monitor_factory( + io_service_, scan_interval_millis); thumbnail_generator_.reset(new thumbnail_generator( monitor_factory, env::media_folder(), @@ -308,7 +373,8 @@ struct server::implementation : boost::noncopyable core::video_format_desc::get(pt.get(L"configuration.thumbnails.video-mode", L"720p2500")), ogl_, pt.get(L"configuration.thumbnails.generate-delay-millis", 2000), - &image::write_cropped_png)); + &image::write_cropped_png, + media_info_repo_)); CASPAR_LOG(info) << L"Initialized thumbnail generator."; } @@ -316,7 +382,7 @@ struct server::implementation : boost::noncopyable safe_ptr create_protocol(const std::wstring& name) const { if(boost::iequals(name, L"AMCP")) - return make_safe(channels_, thumbnail_generator_, shutdown_server_now_); + return make_safe(channels_, thumbnail_generator_, media_info_repo_, shutdown_server_now_); else if(boost::iequals(name, L"CII")) return make_safe(channels_); else if(boost::iequals(name, L"CLOCK")) @@ -328,6 +394,25 @@ struct server::implementation : boost::noncopyable BOOST_THROW_EXCEPTION(caspar_exception() << arg_name_info("name") << arg_value_info(narrow(name)) << msg_info("Invalid protocol")); } + + void start_initial_media_info_scan() + { + initial_media_info_thread_ = boost::thread([this] + { + for (boost::filesystem::wrecursive_directory_iterator iter(env::media_folder()), end; iter != end; ++iter) + { + if (running_) + media_info_repo_->get(iter->path().file_string()); + else + { + CASPAR_LOG(info) << L"Initial media information retrieval aborted."; + return; + } + } + + CASPAR_LOG(info) << L"Initial media information retrieval finished."; + }); + } }; server::server(boost::promise& shutdown_server_now) : impl_(new implementation(shutdown_server_now)){} @@ -342,9 +427,14 @@ std::shared_ptr server::get_thumbnail_generator() const return impl_->thumbnail_generator_; } -core::monitor::source& server::monitor_output() +safe_ptr server::get_media_info_repo() const +{ + return impl_->media_info_repo_; +} + +core::monitor::subject& server::monitor_output() { - return impl_->monitor_subject_; + return *impl_->monitor_subject_; } } \ No newline at end of file