2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG.
\r
6 * CasparCG is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * CasparCG is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License
\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
\r
21 #include "../StdAfx.h"
\r
25 #include <algorithm>
\r
26 #include "CIIProtocolStrategy.h"
\r
27 #include "CIICommandsimpl.h"
\r
28 #include <modules/flash/producer/flash_producer.h>
\r
29 #include <core/producer/transition/transition_producer.h>
\r
30 #include <core/mixer/mixer.h>
\r
31 #include <common/env.h>
\r
33 #if defined(_MSC_VER)
\r
34 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
\r
37 namespace caspar { namespace protocol { namespace cii {
\r
39 using namespace core;
\r
41 const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");
\r
42 const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');
\r
44 CIIProtocolStrategy::CIIProtocolStrategy(const std::vector<safe_ptr<core::video_channel>>& channels) : pChannel_(channels.at(0)), executor_(L"CIIProtocolStrategy")
\r
48 void CIIProtocolStrategy::Parse(const TCHAR* pData, int charCount, IO::ClientInfoPtr pClientInfo)
\r
51 std::wstring msg(pData, charCount);
\r
52 std::wstring availibleData = currentMessage_ + msg;
\r
56 pos = availibleData.find(MessageDelimiter);
\r
57 if(pos != std::wstring::npos)
\r
59 std::wstring message = availibleData.substr(0,pos);
\r
61 if(message.length() > 0) {
\r
62 ProcessMessage(message);
\r
63 if(pClientInfo != 0)
\r
64 pClientInfo->Send(TEXT("*\r\n"));
\r
67 std::size_t nextStartPos = pos + MessageDelimiter.length();
\r
68 if(nextStartPos < availibleData.length())
\r
69 availibleData = availibleData.substr(nextStartPos);
\r
72 availibleData.clear();
\r
79 currentMessage_ = availibleData;
\r
82 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message)
\r
84 CASPAR_LOG(debug) << message.c_str();
\r
86 std::vector<std::wstring> tokens;
\r
87 int tokenCount = TokenizeMessage(message, &tokens);
\r
89 CIICommandPtr pCommand = Create(tokens[0]);
\r
90 if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters())
\r
92 pCommand->Setup(tokens);
\r
93 executor_.begin_invoke([=]{pCommand->Execute();});
\r
95 else {} //report error
\r
98 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
\r
100 std::wstringstream currentToken;
\r
102 for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex)
\r
104 if(message[charIndex] == TokenDelimiter)
\r
106 pTokenVector->push_back(currentToken.str());
\r
107 currentToken.str(TEXT(""));
\r
111 if(message[charIndex] == TEXT('\"'))
\r
112 currentToken << TEXT(""");
\r
113 else if(message[charIndex] == TEXT('<'))
\r
114 currentToken << TEXT("<");
\r
115 else if(message[charIndex] == TEXT('>'))
\r
116 currentToken << TEXT(">");
\r
118 currentToken << message[charIndex];
\r
121 if(currentToken.str().size() > 0)
\r
122 pTokenVector->push_back(currentToken.str());
\r
124 return (int)pTokenVector->size();
\r
128 // Examples (<X> = ASCIICHAR X)
\r
130 I\25\3\VII\\ sätter outputtype till 'vii'
\r
131 I\25\4\1\\ enablar framebuffer (ignore this)
\r
133 M\C/SVTNEWS\\ pekar ut vilken grafisk profil som skall användas
\r
135 W\4009\4067\Jonas Björkman\\ Skriver "Jonas Björkman" till första textfältet i template 4067 och sparar den färdiga skylten som 4009
\r
137 T\7\4009.VII\A\\ lägger ut skylt 4009
\r
139 Y\<205><247><202><196><192><192><200><248>\\ lägger ut skylten 4008 (<205><247><202><196><192><192><200><248> = "=g:4008h" om man drar bort 144 från varje asciivärde)
\r
141 V\5\3\1\1\namn.tga\1\\ lägger ut bilden namn.tga
\r
142 V\0\1\D\C\10\0\0\0\\ gör någon inställning som har med föregående kommando att göra.
\r
146 /**********************
\r
147 New Commands to support the Netupe automation system
\r
148 V\5\13\1\1\Template\0\TabField1\TabField2...\\ Build. Ettan före Template indikerar vilket lager den nya templaten skall laddas in i. OBS. Skall inte visas efter det här steget
\r
149 Y\<27>\\ Stop. Här kommer ett lagerID också att skickas med (<27> = ESC)
\r
150 Y\<254>\\ Clear Canvas. Här kommer ett lagerID också att skickas med, utan det skall allt tömmas
\r
151 Y\<213><243>\\ Play. Här kommer ett lagerID också att skickas med
\r
153 **********************/
\r
154 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
\r
158 case TEXT('M'): return std::make_shared<MediaCommand>(this);
\r
159 case TEXT('W'): return std::make_shared<WriteCommand>(this);
\r
160 case TEXT('T'): return std::make_shared<ImagestoreCommand>(this);
\r
161 case TEXT('V'): return std::make_shared<MiscellaneousCommand>(this);
\r
162 case TEXT('Y'): return std::make_shared<KeydataCommand>(this);
\r
163 default: return nullptr;
\r
167 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData)
\r
169 std::wstring fullTemplateFilename = env::template_folder();
\r
170 if(currentProfile_.size() > 0)
\r
172 fullTemplateFilename += currentProfile_;
\r
173 fullTemplateFilename += TEXT("\\");
\r
175 fullTemplateFilename += templateName;
\r
176 fullTemplateFilename = flash::find_template(fullTemplateFilename);
\r
177 if(fullTemplateFilename.empty())
\r
179 CASPAR_LOG(error) << "Failed to save instance of " << templateName << TEXT(" as ") << titleName << TEXT(", template ") << fullTemplateFilename << " not found";
\r
183 auto producer = flash::create_producer(this->GetChannel()->mixer(), boost::assign::list_of(env::template_folder()+TEXT("CG.fth")));
\r
185 std::wstringstream flashParam;
\r
186 flashParam << TEXT("<invoke name=\"Add\" returntype=\"xml\"><arguments><number>1</number><string>") << currentProfile_ << '/' << templateName << TEXT("</string><number>0</number><true/><string> </string><string><![CDATA[ ") << xmlData << TEXT(" ]]></string></arguments></invoke>");
\r
187 producer->param(flashParam.str());
\r
189 CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;
\r
191 PutPreparedTemplate(titleName, safe_ptr<core::frame_producer>(std::move(producer)));
\r
195 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
\r
199 pChannel_->stage()->load(0, GetPreparedTemplate(titleName));
\r
200 pChannel_->stage()->play(0);
\r
202 CASPAR_LOG(info) << L"Displayed title " << titleName ;
\r
204 catch(caspar_exception&)
\r
206 CASPAR_LOG(error) << L"Failed to display title " << titleName;
\r
210 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename)
\r
212 transition_info transition;
\r
213 transition.type = transition::mix;
\r
214 transition.duration = 12;
\r
216 auto pFP = create_producer(GetChannel()->mixer(), boost::assign::list_of(filename));
\r
217 auto pTransition = create_transition_producer(GetChannel()->get_video_format_desc().field_mode, pFP, transition);
\r
221 pChannel_->stage()->load(0, pTransition);
\r
225 CASPAR_LOG_CURRENT_EXCEPTION();
\r
226 CASPAR_LOG(error) << L"Failed to display " << filename ;
\r
230 pChannel_->stage()->play(0);
\r
232 CASPAR_LOG(info) << L"Displayed " << filename;
\r
235 safe_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
\r
237 safe_ptr<core::frame_producer> result(frame_producer::empty());
\r
239 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
240 if(it != titles_.end()) {
\r
241 CASPAR_LOG(debug) << L"Found title with name " << it->titleName;
\r
242 result = (*it).pframe_producer;
\r
245 CASPAR_LOG(error) << L"Could not find title with name " << titleName;
\r
250 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<core::frame_producer>& pFP)
\r
252 CASPAR_LOG(debug) << L"Saved title with name " << titleName;
\r
254 TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
\r
255 if(it != titles_.end()) {
\r
256 titles_.remove((*it));
\r
259 titles_.push_front(TitleHolder(titleName, pFP));
\r
261 if(titles_.size() >= 6)
\r
265 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs)
\r
267 return lhs.titleName == rhs;
\r
270 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
\r
272 return lhs == rhs.titleName;
\r