Example #1
0
	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++);
					}
				}
			}
		}
	}
Example #2
0
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();
		}
	});
}
Example #3
0
	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();
		}
	}
Example #4
0
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);
}
Example #5
0
	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();});
	}
Example #6
0
	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();
		}
	}
Example #7
0
	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();});
	}
Example #8
0
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;
}
Example #9
0
	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();
		}		
	}
Example #10
0
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";
}
Example #11
0
	~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(...){}
		}
	}
Example #12
0
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);
}
Example #13
0
	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();
		}
	}
Example #14
0
	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;
	}
Example #15
0
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;
}
Example #16
0
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"&lt;";
							else if (currentByte == L'>')
								parameters_.back() += L"&gt;";
							else if (currentByte == L'\"')
								parameters_.back() += L"&quot;";
							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();
			}
		}
	}
Example #18
0
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.";
	}
}
Example #19
0
        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;
Example #20
0
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();
					}
				}
			});
Example #21
0
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;
}
Example #22
0
	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();
		}		
	}