]> git.sesse.net Git - casparcg/blobdiff - protocol/clk/CLKProtocolStrategy.cpp
[ffmpeg_producer] Recognize .mkv and .mxf files as playable without probing
[casparcg] / protocol / clk / CLKProtocolStrategy.cpp
index 5f22d38d162d9b9ddddafa06cf835dffb72b37bc..866a0bc3922e035f3471576218be379d82a8e4fa 100644 (file)
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
\r
-#include "..\stdafx.h"\r
-\r
-#include "CLKProtocolStrategy.h"\r
-\r
-#include <modules/flash/producer/cg_producer.h>\r
-\r
-#include <string>\r
-#include <sstream>\r
-#include <algorithm>\r
-\r
-namespace caspar { namespace protocol { namespace CLK {\r
-       \r
-CLKProtocolStrategy::CLKProtocolStrategy(const std::vector<safe_ptr<core::channel>>& channels) \r
-       : currentState_(ExpectingNewCommand), bClockLoaded_(false), pChannel_(channels.at(0))\r
-{}\r
-\r
-void CLKProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo) \r
-{\r
-       for(int index = 0; index < charCount; ++index) \r
-       {\r
-               if(currentState_ == ExpectingNewCommand)\r
-                       currentCommandString_.str(TEXT(""));\r
-\r
-               TCHAR currentByte = pData[index];\r
-               if(currentByte < 32)\r
-                       currentCommandString_ << TEXT("<") << (int)currentByte << TEXT(">");\r
-               else\r
-                       currentCommandString_ << currentByte;\r
-\r
-               if(currentByte != 0)\r
-               {\r
-                       switch(currentState_)\r
-                       {\r
-                               case ExpectingNewCommand:\r
-                                       if(currentByte == 1) \r
-                                               currentState_ = ExpectingCommand;                                       \r
-                                       //just throw anything else away\r
-                                       break;\r
-\r
-                               case ExpectingCommand:\r
-                                       if(currentByte == 2) \r
-                                       {\r
-                                               if(!currentCommand_.SetCommand()) \r
-                                               {\r
-                                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";\r
-                                                       currentState_ = ExpectingNewCommand;\r
-                                                       currentCommand_.Clear();\r
-                                               }\r
-                                               else \r
-                                                       currentState_ = ExpectingClockID;                                               \r
-                                       }\r
-                                       else\r
-                                               currentCommand_.commandString_ += currentByte;\r
-                                       break;\r
-\r
-                               case ExpectingClockID:\r
-                                       if(currentByte == 2)\r
-                                               currentState_ = currentCommand_.NeedsTime() ? ExpectingTime : ExpectingParameter;\r
-                                       else\r
-                                               currentCommand_.clockID_ = currentByte - TCHAR('0');\r
-                                       break;\r
-\r
-                               case ExpectingTime:\r
-                                       if(currentByte == 2)\r
-                                               currentState_ = ExpectingParameter;\r
-                                       else\r
-                                               currentCommand_.time_ += currentByte;\r
-                                       break;\r
-\r
-                               case ExpectingParameter:\r
-                                       //allocate new parameter\r
-                                       if(currentCommand_.parameters_.size() == 0 || currentByte == 2)\r
-                                               currentCommand_.parameters_.push_back(std::wstring());\r
-\r
-                                       //add the character to end end of the last parameter\r
-                                       if(currentByte == TEXT('<'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&lt;");\r
-                                       else if(currentByte == TEXT('>'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&gt;");\r
-                                       else if(currentByte == TEXT('\"'))\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += TEXT("&quot;");\r
-                                       else\r
-                                               currentCommand_.parameters_[currentCommand_.parameters_.size()-1] += currentByte;\r
-\r
-                                       break;\r
-                       }\r
-               }\r
-               else \r
-               {\r
-                       if(currentState_ == ExpectingCommand)\r
-                       {\r
-                               if(!currentCommand_.SetCommand())\r
-                                       CASPAR_LOG(error) << "CLK: Failed to interpret command";\r
-                       }\r
-\r
-                       if(currentCommand_.command_ == CLKCommand::CLKReset) \r
-                       {\r
-                               pChannel_->producer()->clear(cg_producer::DEFAULT_LAYER);\r
-                               bClockLoaded_ = false;\r
-                               \r
-                               CASPAR_LOG(info) << L"CLK: Recieved and executed reset-command";\r
-                       }\r
-                       else if(currentCommand_.command_ != CLKCommand::CLKInvalidCommand)\r
-                       {\r
-                               if(!bClockLoaded_) \r
-                               {\r
-                                       get_default_cg_producer(pChannel_)->add(0, TEXT("hawrysklocka/clock.ft"), true, TEXT(""), currentCommand_.GetData());\r
-                                       bClockLoaded_ = true;\r
-                               }\r
-                               else \r
-                                       get_default_cg_producer(pChannel_)->update(0, currentCommand_.GetData());\r
-                               \r
-                               CASPAR_LOG(debug) << L"CLK: Clockdata sent: " << currentCommand_.GetData();\r
-                               CASPAR_LOG(debug) << L"CLK: Executed valid command: " << currentCommandString_.str();\r
-                       }\r
-\r
-                       currentState_ = ExpectingNewCommand;\r
-                       currentCommand_.Clear();\r
-               }\r
-       }\r
-}\r
-\r
-}      //namespace CLK\r
-}}     //namespace caspar
\ No newline at end of file
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Nicklas P Andersson
+*/
+
+#include "../StdAfx.h"
+
+#include "CLKProtocolStrategy.h"
+#include "clk_commands.h"
+
+#include <string>
+#include <algorithm>
+#include <locale>
+#include <vector>
+#include <sstream>
+
+namespace caspar { namespace protocol { namespace CLK {
+
+class CLKProtocolStrategy : public IO::protocol_strategy<wchar_t>
+{
+       enum class ParserState
+       {
+               ExpectingNewCommand,
+               ExpectingCommand,
+               ExpectingParameter
+       };
+
+       ParserState     currentState_                                                           = ParserState::ExpectingNewCommand;
+       std::wstringstream currentCommandString_;
+       std::wstring command_name_;
+       std::vector<std::wstring> parameters_;
+       clk_command_processor& command_processor_;
+       IO::client_connection<wchar_t>::ptr client_connection_;
+public:
+       CLKProtocolStrategy(
+                       const IO::client_connection<wchar_t>::ptr& client_connection,
+                       clk_command_processor& command_processor) 
+               : command_processor_(command_processor)
+               , client_connection_(client_connection)
+       {
+       }
+
+       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 ParserState::ExpectingNewCommand:
+                                               if (currentByte == 1) 
+                                                       currentState_ = ParserState::ExpectingCommand;
+                                               //just throw anything else away
+                                               break;
+                                       case ParserState::ExpectingCommand:
+                                               if (currentByte == 2) 
+                                                       currentState_ = ParserState::ExpectingParameter;
+                                               else
+                                                       command_name_ += currentByte;
+                                               break;
+                                       case ParserState::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(info) << L"CLK: Executed valid command: " 
+                                                       << currentCommandString_.str();
+                               } 
+                               catch (...)
+                               {
+                                       CASPAR_LOG_CURRENT_EXCEPTION();
+                                       CASPAR_LOG(error) << "CLK: Failed to interpret command: " 
+                                               << currentCommandString_.str();
+                               }
+
+                               reset();
+                       }
+               }
+       }
+private:
+       void reset()
+       {
+               currentState_ = ParserState::ExpectingNewCommand;
+               currentCommandString_.str(L"");
+               command_name_.clear();
+               parameters_.clear();
+       }
+};
+
+clk_protocol_strategy_factory::clk_protocol_strategy_factory(
+               const std::vector<spl::shared_ptr<core::video_channel>>& channels,
+               const spl::shared_ptr<core::cg_producer_registry>& cg_registry,
+               const spl::shared_ptr<const core::frame_producer_registry>& producer_registry)
+{
+       add_command_handlers(command_processor_, channels, channels.at(0), cg_registry, producer_registry);
+}
+
+IO::protocol_strategy<wchar_t>::ptr clk_protocol_strategy_factory::create(
+               const IO::client_connection<wchar_t>::ptr& client_connection)
+{
+       return spl::make_shared<CLKProtocolStrategy>(client_connection, command_processor_);
+}
+
+}}}