void execute(const safe_ptr<read_frame>& frame) { if(!has_synchronization_clock()) timer_.tick(1.0/channel_.get_format_desc().fps); if(frame->image_size() != channel_.get_format_desc().size) { timer_.tick(1.0/channel_.get_format_desc().fps); return; } auto it = consumers_.begin(); while(it != consumers_.end()) { auto consumer = it->second; if(consumer->get_video_format_desc() != channel_.get_format_desc()) consumer->initialize(channel_.get_format_desc()); try { if(consumer->send(frame)) ++it; else consumers_.erase(it++); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(warning) << "Trying to restart consumer: " << consumer->print() << L"."; try { consumer->initialize(channel_.get_format_desc()); consumer->send(frame); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(warning) << "Consumer restart failed, trying to restart channel: " << consumer->print() << L"."; try { restart_channel_(); consumer->initialize(channel_.get_format_desc()); consumer->send(frame); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << "Failed to recover consumer: " << consumer->print() << L". Removing it."; consumers_.erase(it++); } } } } }
void AMCPCommandQueue::AddCommand(AMCPCommandPtr pCurrentCommand) { if(!pCurrentCommand) return; if(pCurrentCommand->GetScheduling() == ImmediatelyAndClear) executor_.clear(); if(executor_.size() > 64) { try { CASPAR_LOG(error) << "AMCP Command Queue Overflow."; CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print(); pCurrentCommand->SetReplyString(L"500 FAILED\r\n"); pCurrentCommand->SendReply(); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } } executor_.begin_invoke([=] { try { try { if(pCurrentCommand->Execute()) CASPAR_LOG(debug) << "Executed command: " << pCurrentCommand->print(); else CASPAR_LOG(warning) << "Failed to execute command: " << pCurrentCommand->print(); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << "Failed to execute command:" << pCurrentCommand->print(); pCurrentCommand->SetReplyString(L"500 FAILED\r\n"); } pCurrentCommand->SendReply(); CASPAR_LOG(trace) << "Ready for a new command"; } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } }); }
safe_ptr<basic_frame> receive() { try { if(is_paused_) return disable_audio(foreground_->last_frame()); auto frame = receive_and_follow(foreground_, frame_producer::NO_HINT); if(frame == core::basic_frame::late()) return foreground_->last_frame(); auto frames_left = foreground_->nb_frames() - (++frame_number_) - auto_play_delta_; if(auto_play_delta_ > -1 && frames_left < 1) { play(); return receive(); } return frame; } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); stop(); return core::basic_frame::empty(); } }
spl::shared_ptr<shader> get_image_shader(bool& blend_modes) { tbb::mutex::scoped_lock lock(g_shader_mutex); if(g_shader) { blend_modes = g_blend_modes; return spl::make_shared_ptr(g_shader); } try { g_blend_modes = glTextureBarrierNV ? env::properties().get(L"configuration.blend-modes", true) : false; g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes))); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes."; g_blend_modes = false; g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes))); } //if(!g_blend_modes) //{ // ogl.blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); // CASPAR_LOG(info) << L"[shader] Blend-modes are disabled."; //} blend_modes = g_blend_modes; return spl::make_shared_ptr(g_shader); }
void tick() { if(!window_) return; sf::Event e; while(window_->GetEvent(e)) { if(e.Type == sf::Event::Closed) { window_.reset(); return; } } try { glClear(GL_COLOR_BUFFER_BIT); window_->Draw(*this); window_->Display(); boost::this_thread::sleep(boost::posix_time::milliseconds(10)); } catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << L"Closing diag window due to error during rendering"; window_.reset(); return; } executor_.begin_invoke([this]{tick();}); }
safe_ptr<basic_frame> receive(int hints) { try { if(is_paused_) return disable_audio(foreground_->last_frame()); auto frame = receive_and_follow(foreground_, hints); if(frame == core::basic_frame::late()) return foreground_->last_frame(); auto frames_left = static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(++frame_number_) - static_cast<int64_t>(auto_play_delta_); if(auto_play_delta_ > -1 && frames_left < 1) { play(); return receive(hints); } return frame; } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); stop(); return core::basic_frame::empty(); } }
void tick() { try { auto format_desc = video_format_desc(); boost::timer frame_timer; // Produce auto stage_frames = stage_(format_desc); // Mix auto mixed_frame = mixer_(std::move(stage_frames), format_desc); // Consume output_(std::move(mixed_frame), format_desc); graph_->set_value("tick-time", frame_timer.elapsed()*format_desc.fps*0.5); event_subject_ << monitor::event("profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps) << monitor::event("format") % format_desc.name; } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } executor_.begin_invoke([=]{tick();}); }
safe_ptr<core::frame_producer> do_create_producer(const safe_ptr<frame_factory>& my_frame_factory, const core::parameters& params, const std::vector<const producer_factory_t>& factories, bool throw_on_fail = false) { if(params.empty()) BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info("")); auto producer = frame_producer::empty(); std::any_of(factories.begin(), factories.end(), [&](const producer_factory_t& factory) -> bool { try { producer = factory(my_frame_factory, params); } catch(...) { if (throw_on_fail) throw; else CASPAR_LOG_CURRENT_EXCEPTION(); } return producer != frame_producer::empty(); }); if(producer == frame_producer::empty()) producer = create_color_producer(my_frame_factory, params); return producer; }
void tick(const std::weak_ptr<implementation>& self) { try { produce_timer_.restart(); std::map<int, safe_ptr<basic_frame>> frames; BOOST_FOREACH(auto& layer, layers_) frames[layer.first] = basic_frame::empty(); tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) { auto transform = transforms_[layer.first].fetch_and_tick(1); int hints = frame_producer::NO_HINT; if(format_desc_.field_mode != field_mode::progressive) { hints |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; } if(transform.is_key) hints |= frame_producer::ALPHA_HINT; auto frame = layer.second.receive(hints); auto frame1 = make_safe<core::basic_frame>(frame); frame1->get_frame_transform() = transform; if(format_desc_.field_mode != core::field_mode::progressive) { auto frame2 = make_safe<core::basic_frame>(frame); frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1); frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode); } frames[layer.first] = frame1; }); graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); std::shared_ptr<void> ticket(nullptr, [self](void*) { auto self2 = self.lock(); if(self2) self2->executor_.begin_invoke([=]{tick(self);}); }); target_->send(std::make_pair(frames, ticket)); graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); tick_timer_.restart(); } catch(...) { layers_.clear(); CASPAR_LOG_CURRENT_EXCEPTION(); } }
void AMCPCommandQueue::Run(HANDLE stopEvent) { bool logTemporarilyBadState = true; AMCPCommandPtr pCurrentCommand; CASPAR_LOG(info) << "AMCP CommandPump started"; while(WaitForSingleObject(stopEvent, 0) != WAIT_OBJECT_0) { DWORD waitResult = WaitForSingleObject(newCommandEvent_, 50); if(waitResult == WAIT_OBJECT_0) { tbb::mutex::scoped_lock lock(mutex_); if(commands_.size() > 0) { CASPAR_LOG(debug) << "Found " << commands_.size() << " commands in queue"; AMCPCommandPtr pNextCommand = commands_.front(); if(pCurrentCommand == 0 || pNextCommand->GetScheduling() == ImmediatelyAndClear) { pCurrentCommand = pNextCommand; commands_.pop_front(); } } } if(pCurrentCommand != 0) { try { if(pCurrentCommand->Execute()) CASPAR_LOG(info) << "Executed command: " << pCurrentCommand->print(); else CASPAR_LOG(info) << "Failed to execute command: " << pCurrentCommand->print(); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(info) << "Failed to execute command:" << pCurrentCommand->print(); } pCurrentCommand->SendReply(); pCurrentCommand.reset(); newCommandEvent_.Set(); logTemporarilyBadState = true; CASPAR_LOG(info) << "Ready for a new command"; } } CASPAR_LOG(info) << "CommandPump ended"; }
~destroy_producer_proxy() { static auto destroyers = std::make_shared<tbb::concurrent_bounded_queue<std::shared_ptr<executor>>>(); static tbb::atomic<int> destroyer_count; try { std::shared_ptr<executor> destroyer; if(!destroyers->try_pop(destroyer)) { destroyer.reset(new executor(L"destroyer")); destroyer->set_priority_class(below_normal_priority_class); if(++destroyer_count > 16) CASPAR_LOG(warning) << L"Potential destroyer dead-lock detected."; CASPAR_LOG(trace) << "Created destroyer: " << destroyer_count; } auto producer = producer_.release(); auto pool = destroyers; destroyer->begin_invoke([=] { std::unique_ptr<std::shared_ptr<frame_producer>> producer2(producer); auto str = (*producer2)->print(); try { if(!producer->unique()) CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count(); else CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread."; } catch(...){} producer2.reset(); pool->push(destroyer); }); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); try { producer_.reset(); } catch(...){} } }
safe_ptr<shader> get_image_shader( ogl_device& ogl, bool& blend_modes, bool& post_processing) { tbb::mutex::scoped_lock lock(g_shader_mutex); if(g_shader) { blend_modes = g_blend_modes; post_processing = g_post_processing; return make_safe_ptr(g_shader); } bool chroma_key = env::properties().get(L"configuration.mixer.chroma-key", false); bool straight_alpha = env::properties().get(L"configuration.mixer.straight-alpha", false); g_post_processing = straight_alpha; try { g_blend_modes = glTextureBarrierNV ? env::properties().get(L"configuration.mixer.blend-modes", false) : false; g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes, chroma_key, g_post_processing))); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes."; g_blend_modes = false; g_shader.reset(new shader(get_vertex(), get_fragment(g_blend_modes, chroma_key, g_post_processing))); } ogl.enable(GL_TEXTURE_2D); if(!g_blend_modes) { ogl.enable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE); CASPAR_LOG(info) << L"[shader] Blend-modes are disabled."; } blend_modes = g_blend_modes; post_processing = g_post_processing; return make_safe_ptr(g_shader); }
safe_ptr<basic_frame> receive(int hints) { try { monitor_subject_ << monitor::message("/paused") % is_paused_; if(is_paused_) { if(foreground_->last_frame() == basic_frame::empty()) foreground_->receive(frame_producer::NO_HINT); return disable_audio(foreground_->last_frame()); } auto foreground = foreground_; auto frame = receive_and_follow(foreground, hints); if(foreground != foreground_) set_foreground(foreground); if(frame == core::basic_frame::late()) return foreground_->last_frame(); auto frames_left = static_cast<int64_t>(foreground_->nb_frames()) - static_cast<int64_t>(++frame_number_) - static_cast<int64_t>(auto_play_delta_); if(auto_play_delta_ > -1 && frames_left < 1) { play(); return receive(hints); } return frame; } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); stop(); return core::basic_frame::empty(); } }
virtual bool send(const safe_ptr<core::read_frame>& frame) override { auto format_desc = format_desc_; boost::thread async([format_desc, frame] { try { auto filename = narrow(env::data_folder()) + boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time()) + ".png"; auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Allocate(format_desc.width, format_desc.height, 32), FreeImage_Unload); memcpy(FreeImage_GetBits(bitmap.get()), frame->image_data().begin(), frame->image_size()); FreeImage_FlipVertical(bitmap.get()); FreeImage_Save(FIF_PNG, bitmap.get(), filename.c_str(), 0); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } }); async.detach(); return false; }
safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params) { if(params.empty()) BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info("")); auto consumer = frame_consumer::empty(); std::any_of(g_factories.begin(), g_factories.end(), [&](const consumer_factory_t& factory) -> bool { try { consumer = factory(params); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } return consumer != frame_consumer::empty(); }); if(consumer == frame_consumer::empty()) BOOST_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.")); return consumer; }
int main(int argc, wchar_t* argv[]) { static_assert(sizeof(void*) == 4, "64-bit code generation is not supported."); SetUnhandledExceptionFilter(UserUnhandledExceptionFilter); setup_global_locale(); std::wcout << L"Type \"q\" to close application." << std::endl; // Set debug mode. #ifdef _DEBUG HANDLE hLogFile; hLogFile = CreateFile(L"crt_log.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); std::shared_ptr<void> crt_log(nullptr, [](HANDLE h){::CloseHandle(h);}); _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, hLogFile); _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ERROR, hLogFile); _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_ASSERT, hLogFile); #endif // Increase process priotity. SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); // Install structured exception handler. caspar::win32_exception::install_handler(); // Increase time precision. This will increase accuracy of function like Sleep(1) from 10 ms to 1 ms. struct inc_prec { inc_prec(){timeBeginPeriod(1);} ~inc_prec(){timeEndPeriod(1);} } inc_prec; // Install unstructured exception handlers into all tbb threads. struct tbb_thread_installer : public tbb::task_scheduler_observer { tbb_thread_installer(){observe(true);} void on_scheduler_entry(bool is_worker) { //caspar::detail::SetThreadName(GetCurrentThreadId(), "tbb-worker-thread"); caspar::win32_exception::install_handler(); } } tbb_thread_installer; tbb::task_scheduler_init init; try { // Configure environment properties from configuration. caspar::env::configure(L"casparcg.config"); caspar::log::set_log_level(caspar::env::properties().get(L"configuration.log-level", L"debug")); #ifdef _DEBUG if(caspar::env::properties().get(L"configuration.debugging.remote", false)) MessageBox(nullptr, TEXT("Now is the time to connect for remote debugging..."), TEXT("Debug"), MB_OK | MB_TOPMOST); #endif // Start logging to file. caspar::log::add_file_sink(caspar::env::log_folder()); std::wcout << L"Logging [info] or higher severity to " << caspar::env::log_folder() << std::endl << std::endl; // Setup console window. setup_console_window(); // Print environment information. print_info(); std::wstringstream str; boost::property_tree::xml_writer_settings<wchar_t> w(' ', 3); boost::property_tree::write_xml(str, caspar::env::properties(), w); CASPAR_LOG(info) << L"casparcg.config:\n-----------------------------------------\n" << str.str().c_str() << L"-----------------------------------------"; bool wait_for_keypress; { boost::promise<bool> shutdown_server_now; boost::unique_future<bool> shutdown_server = shutdown_server_now.get_future(); // Create server object which initializes channels, protocols and controllers. caspar::server caspar_server(shutdown_server_now); // Use separate thread for the blocking console input, will be terminated // anyway when the main thread terminates. boost::thread stdin_thread([&caspar_server, &shutdown_server_now] { // Create a amcp parser for console commands. caspar::protocol::amcp::AMCPProtocolStrategy amcp( caspar_server.get_channels(), caspar_server.get_thumbnail_generator(), shutdown_server_now); // Create a dummy client which prints amcp responses to console. auto console_client = std::make_shared<caspar::IO::ConsoleClientInfo>(); std::wstring wcmd; while(true) { std::getline(std::wcin, wcmd); // TODO: It's blocking... //boost::to_upper(wcmd); // TODO COMPILER crashes on this line, Strange! make_upper_case(wcmd); if(wcmd == L"EXIT" || wcmd == L"Q" || wcmd == L"QUIT" || wcmd == L"BYE") { shutdown_server_now.set_value(true); // True to wait for keypress break; } try { // This is just dummy code for testing. if(wcmd.substr(0, 1) == L"1") wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" SLIDE 100 LOOP \r\nPLAY 1-1"; else if(wcmd.substr(0, 1) == L"2") wcmd = L"MIXER 1-0 VIDEO IS_KEY 1"; else if(wcmd.substr(0, 1) == L"3") wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1"; else if(wcmd.substr(0, 1) == L"4") wcmd = L"PLAY 1-1 DV FILTER yadif=1:-1 LOOP"; else if(wcmd.substr(0, 1) == L"5") { auto file = wcmd.substr(2, wcmd.length()-1); wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" L"PLAY 1-2 " + file + L" LOOP\r\n" L"PLAY 1-3 " + file + L" LOOP\r\n" L"PLAY 2-1 " + file + L" LOOP\r\n" L"PLAY 2-2 " + file + L" LOOP\r\n" L"PLAY 2-3 " + file + L" LOOP\r\n"; } else if(wcmd.substr(0, 1) == L"X") { int num = 0; std::wstring file; try { num = boost::lexical_cast<int>(wcmd.substr(1, 2)); file = wcmd.substr(4, wcmd.length()-1); } catch(...) { num = boost::lexical_cast<int>(wcmd.substr(1, 1)); file = wcmd.substr(3, wcmd.length()-1); } int n = 0; int num2 = num; while(num2 > 0) { num2 >>= 1; n++; } wcmd = L"MIXER 1 GRID " + boost::lexical_cast<std::wstring>(n); for(int i = 1; i <= num; ++i) wcmd += L"\r\nPLAY 1-" + boost::lexical_cast<std::wstring>(i) + L" " + file + L" LOOP";// + L" SLIDE 100 LOOP"; } } catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); continue; } wcmd += L"\r\n"; amcp.Parse(wcmd.c_str(), wcmd.length(), console_client); } }); stdin_thread.detach(); wait_for_keypress = shutdown_server.get(); } Sleep(500); CASPAR_LOG(info) << "Successfully shutdown CasparCG Server."; if (wait_for_keypress) system("pause"); }
void parse(const std::basic_string<wchar_t>& data) { for (int index = 0; index < data.length(); ++index) { wchar_t currentByte = data[index]; if (currentByte < 32) currentCommandString_ << L"<" << static_cast<int>(currentByte) << L">"; else currentCommandString_ << currentByte; if (currentByte != 0) { switch (currentState_) { case ExpectingNewCommand: if (currentByte == 1) currentState_ = ExpectingCommand; //just throw anything else away break; case ExpectingCommand: if (currentByte == 2) currentState_ = ExpectingParameter; else command_name_ += currentByte; break; case ExpectingParameter: //allocate new parameter if (parameters_.size() == 0 || currentByte == 2) parameters_.push_back(std::wstring()); //add the character to end end of the last parameter if (currentByte != 2) { //add the character to end end of the last parameter if (currentByte == L'<') parameters_.back() += L"<"; else if (currentByte == L'>') parameters_.back() += L">"; else if (currentByte == L'\"') parameters_.back() += L"""; else parameters_.back() += currentByte; } break; } } else { std::transform( command_name_.begin(), command_name_.end(), command_name_.begin(), toupper); try { if (!command_processor_.handle(command_name_, parameters_)) CASPAR_LOG(error) << "CLK: Unknown command: " << command_name_; else CASPAR_LOG(debug) << L"CLK: Executed valid command: " << currentCommandString_.str(); } catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << "CLK: Failed to interpret command: " << currentCommandString_.str(); } reset(); } } }
void configure(const std::wstring& filename) { try { auto separator = boost::filesystem::path::preferred_separator; auto initialPath = fs::initial_path<fs::path>().wstring(); std::wstring path_(initialPath + boost::lexical_cast<std::wstring>(separator) + filename); const wchar_t *pstr = path_.c_str(); std::wifstream file(reinterpret_cast<const char *>(pstr)); CASPAR_LOG(info) << L"before read_xml ..." << initialPath << " " << filename << " " << pstr; boost::property_tree::read_xml("/etc/casparcg.config", pt, boost::property_tree::xml_parser::trim_whitespace | boost::property_tree::xml_parser::no_comments); CASPAR_LOG(info) << L"read_xml done..."; auto paths = pt.get_child(L"configuration.paths"); media = widen(paths.get(L"media-path", initialPath + L"/media/")); log = widen(paths.get(L"log-path", initialPath + L"/log/")); ftemplate = fs::complete(fs::path(widen(paths.get(L"template-path", initialPath + L"/template/")))).wstring(); data = widen(paths.get(L"data-path", initialPath + L"/data/")); thumbnails = widen(paths.get(L"thumbnails-path", initialPath + L"/thumbnails/")); //Make sure that all paths have a trailing backslash if(media.at(media.length()-1) != L'/') media.append(L"/"); if(log.at(log.length()-1) != L'/') log.append(L"/"); if(ftemplate.at(ftemplate.length()-1) != L'/') ftemplate.append(L"/"); if(data.at(data.length()-1) != L'/') data.append(L"/"); if(thumbnails.at(thumbnails.length()-1) != L'/') thumbnails.append(L"/"); try { for(auto it = fs::directory_iterator(initialPath); it != fs::directory_iterator(); ++it) { if(it->path().filename().wstring().find(L".fth") != std::wstring::npos) { auto from_path = *it; auto to_path = fs::path(ftemplate + L'/' + it->path().filename().wstring()); if(fs::exists(to_path)) fs::remove(to_path); fs::copy_file(from_path, to_path); } } } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << L"Failed to copy template-hosts from initial-path to template-path."; } } catch(...) { std::wcout << L" ### Invalid configuration file. ###"; throw; } try { auto media_path = fs::path(media); if(!fs::exists(media_path)) fs::create_directory(media_path); auto log_path = fs::path(log); if(!fs::exists(log_path)) fs::create_directory(log_path); auto template_path = fs::path(ftemplate); if(!fs::exists(template_path)) fs::create_directory(template_path); auto data_path = fs::path(data); if(!fs::exists(data_path)) fs::create_directory(data_path); auto thumbnails_path = fs::path(thumbnails); if(!fs::exists(thumbnails_path)) fs::create_directory(thumbnails_path); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); CASPAR_LOG(error) << L"Failed to create configured directories."; } }
graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f)); graph_->set_color("frame-time", diagnostics::color(0.0f, 1.0f, 0.0f)); graph_->set_color("buffer", diagnostics::color(1.0f, 1.0f, 0.0f)); state_["file/name"] = u8(name_); state_["file/path"] = u8(path_); state_["loop"] = loop; update_state(); thread_ = boost::thread([=] { try { run(); } catch (boost::thread_interrupted&) { // Do nothing... } catch (...) { CASPAR_LOG_CURRENT_EXCEPTION(); } }); } ~Impl() { input_.abort(); abort_request_ = true; buffer_cond_.notify_all(); thread_.join(); } void run() { std::vector<int> audio_cadence = format_desc_.audio_cadence;
int main(int argc, wchar_t* argv[]) { static_assert(sizeof(void*) == 4, "64-bit code generation is not supported."); SetUnhandledExceptionFilter(UserUnhandledExceptionFilter); std::wcout << L"Type \"q\" to close application." << std::endl; // Set debug mode. #ifdef _DEBUG _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF ); _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG ); _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG ); _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG ); #endif // Increase process priotity. SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); // Install structured exception handler. caspar::win32_exception::install_handler(); caspar::log::set_log_level(L"debug"); // Increase time precision. This will increase accuracy of function like Sleep(1) from 10 ms to 1 ms. struct inc_prec { inc_prec(){timeBeginPeriod(1);} ~inc_prec(){timeEndPeriod(1);} } inc_prec; // Install unstructured exception handlers into all tbb threads. struct tbb_thread_installer : public tbb::task_scheduler_observer { tbb_thread_installer(){observe(true);} void on_scheduler_entry(bool is_worker) { //caspar::detail::SetThreadName(GetCurrentThreadId(), "tbb-worker-thread"); caspar::win32_exception::install_handler(); } } tbb_thread_installer; tbb::task_scheduler_init init; try { { // Configure environment properties from configuration. caspar::env::configure("casparcg.config"); #ifdef _DEBUG if(caspar::env::properties().get("configuration.debugging.remote", false)) MessageBox(nullptr, TEXT("Now is the time to connect for remote debugging..."), TEXT("Debug"), MB_OK | MB_TOPMOST); #endif // Start logging to file. caspar::log::add_file_sink(caspar::env::log_folder()); std::wcout << L"Logging [info] or higher severity to " << caspar::env::log_folder() << std::endl << std::endl; // Setup console window. setup_console_window(); // Print environment information. print_info(); // Create server object which initializes channels, protocols and controllers. caspar::server caspar_server; // Create a amcp parser for console commands. caspar::protocol::amcp::AMCPProtocolStrategy amcp(caspar_server.get_channels()); // Create a dummy client which prints amcp responses to console. auto console_client = std::make_shared<caspar::IO::ConsoleClientInfo>(); boost::thread input_thread([&] { while(shutdown_event == application_state::running) { std::wstring wcmd; std::getline(std::wcin, wcmd); // TODO: It's blocking... try { if(wcmd == L"exit" || wcmd == L"q") { shutdown_event = application_state::pause_and_shutdown; shutdown_cond.notify_all(); return; } // This is just dummy code for testing. if(wcmd.substr(0, 1) == L"1") wcmd = L"LOADBG 1-1 " + wcmd.substr(1, wcmd.length()-1) + L" SLIDE 100 LOOP \r\nPLAY 1-1"; else if(wcmd.substr(0, 1) == L"2") wcmd = L"MIXER 1-0 VIDEO IS_KEY 1"; else if(wcmd.substr(0, 1) == L"3") wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1"; else if(wcmd.substr(0, 1) == L"4") wcmd = L"PLAY 1-1 DV FILTER yadif=1:-1 LOOP"; else if(wcmd.substr(0, 1) == L"5") { auto file = wcmd.substr(2, wcmd.length()-1); wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" L"PLAY 1-2 " + file + L" LOOP\r\n" L"PLAY 1-3 " + file + L" LOOP\r\n" L"PLAY 2-1 " + file + L" LOOP\r\n" L"PLAY 2-2 " + file + L" LOOP\r\n" L"PLAY 2-3 " + file + L" LOOP\r\n"; } else if(wcmd.substr(0, 1) == L"X") { int num = 0; std::wstring file; try { num = boost::lexical_cast<int>(wcmd.substr(1, 2)); file = wcmd.substr(4, wcmd.length()-1); } catch(...) { num = boost::lexical_cast<int>(wcmd.substr(1, 1)); file = wcmd.substr(3, wcmd.length()-1); } int n = 0; int num2 = num; while(num2 > 0) { num2 >>= 1; n++; } wcmd = L"MIXER 1 GRID " + boost::lexical_cast<std::wstring>(n); for(int i = 1; i <= num; ++i) wcmd += L"\r\nPLAY 1-" + boost::lexical_cast<std::wstring>(i) + L" " + file + L" LOOP";// + L" SLIDE 100 LOOP"; } wcmd += L"\r\n"; amcp.Parse(wcmd.c_str(), wcmd.length(), console_client); } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } } });
std::map<std::string, std::string> read_flv_meta_info(const std::string& filename) { std::map<std::string, std::string> values; if(boost::filesystem2::path(filename).extension() != ".flv") return values; try { if(!boost::filesystem2::exists(filename)) BOOST_THROW_EXCEPTION(caspar_exception()); std::fstream fileStream = std::fstream(filename, std::fstream::in); std::vector<char> bytes2(256); fileStream.read(bytes2.data(), bytes2.size()); auto ptr = bytes2.data(); ptr += 27; if(std::string(ptr, ptr+10) == "onMetaData") { ptr += 16; for(int n = 0; n < 16; ++n) { char name_size = *ptr++; if(name_size == 0) break; auto name = std::string(ptr, ptr + name_size); ptr += name_size; char data_type = *ptr++; switch(data_type) { case 0: // double { static_assert(sizeof(double) == 8, ""); std::reverse(ptr, ptr+8); values[name] = boost::lexical_cast<std::string>(*(double*)(ptr)); ptr += 9; break; } case 1: // bool { values[name] = boost::lexical_cast<std::string>(*ptr != 0); ptr += 2; break; } } } } } catch(...) { CASPAR_LOG_CURRENT_EXCEPTION(); } return values; }
void tick(const std::weak_ptr<implementation>& self) { try { produce_timer_.restart(); std::map<int, safe_ptr<basic_frame>> frames; //fix g++ warning //std::map<int, std::shared_ptr<basic_frame>> frames; for(auto it = layers_.begin(); it != layers_.end(); ++it) frames[it->first] = make_safe<core::basic_frame>(basic_frame::empty()); tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, std::shared_ptr<layer>>::value_type& layer) { auto transform = transforms_[layer.first].fetch_and_tick(1); int hints = frame_producer::NO_HINT; if(format_desc_.field_mode != field_mode::progressive) { hints |= std::abs(transform.fill_scale[1] - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT; } if(transform.is_key) hints |= frame_producer::ALPHA_HINT; auto frame = layer.second->receive(hints); auto layer_consumers_it = layer_consumers_.find(layer.first); if (layer_consumers_it != layer_consumers_.end()) { auto consumer_it = (*layer_consumers_it).second | boost::adaptors::map_values; tbb::parallel_for_each(consumer_it.begin(), consumer_it.end(), [&](decltype(*consumer_it.begin()) layer_consumer) { layer_consumer->send(frame); }); } auto frame1 = make_safe<core::basic_frame>(frame); frame1->get_frame_transform() = transform; if(format_desc_.field_mode != core::field_mode::progressive) { auto frame2 = make_safe<core::basic_frame>(frame); frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1); frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode); } frames[layer.first] = std::move(frame1); }); // Tick the transforms that does not have a corresponding layer. BOOST_FOREACH(auto& elem, transforms_) if (layers_.find(elem.first) == layers_.end()) elem.second.fetch_and_tick(format_desc_.field_mode != core::field_mode::progressive ? 2 : 1); graph_->set_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5); std::shared_ptr<void> ticket(nullptr, [=](void*) { auto self2 = self.lock(); if(self2) self2->executor_.begin_invoke([=]{tick(self);}); }); target_->send(std::make_pair(frames, ticket)); //comment out due to g++ warning fix */ graph_->set_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5); tick_timer_.restart(); } catch(...) { layers_.clear(); CASPAR_LOG_CURRENT_EXCEPTION(); } }