]> git.sesse.net Git - casparcg/blob - protocol/cii/CIIProtocolStrategy.cpp
[decklink] Added missing channel-layer in diag for the producer
[casparcg] / protocol / cii / CIIProtocolStrategy.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Nicklas P Andersson
20 */
21
22  
23 #include "../StdAfx.h"
24
25 #include <string>
26 #include <sstream>
27 #include <algorithm>
28 #include "CIIProtocolStrategy.h"
29 #include "CIICommandsImpl.h"
30 #include <core/producer/transition/transition_producer.h>
31 #include <core/mixer/mixer.h>
32 #include <core/diagnostics/call_context.h>
33 #include <common/env.h>
34
35 #include <boost/algorithm/string/replace.hpp>
36
37 #if defined(_MSC_VER)
38 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings
39 #endif
40
41 namespace caspar { namespace protocol { namespace cii {
42         
43 using namespace core;
44
45 const std::wstring CIIProtocolStrategy::MessageDelimiter = L"\r\n";
46 const wchar_t CIIProtocolStrategy::TokenDelimiter = L'\\';
47
48 CIIProtocolStrategy::CIIProtocolStrategy(
49                 const std::vector<spl::shared_ptr<core::video_channel>>& channels, 
50                 const spl::shared_ptr<core::cg_producer_registry>& cg_registry,
51                 const spl::shared_ptr<const core::frame_producer_registry>& producer_registry)
52         : executor_(L"CIIProtocolStrategy")
53         , pChannel_(channels.at(0))
54         , channels_(channels)
55         , cg_registry_(cg_registry)
56         , producer_registry_(producer_registry)
57 {
58 }
59
60 //The paser method expects message to be complete messages with the delimiter stripped away.
61 //Thesefore the AMCPProtocolStrategy should be decorated with a delimiter_based_chunking_strategy
62 void CIIProtocolStrategy::Parse(const std::wstring& message, IO::ClientInfoPtr client) 
63 {
64         if(message.length() > 0)
65         {
66                 ProcessMessage(message, client);
67                 client->send(std::wstring(L"*\r\n"));
68         }
69 }
70
71 void CIIProtocolStrategy::ProcessMessage(const std::wstring& message, IO::ClientInfoPtr pClientInfo)
72 {       
73         CASPAR_LOG(info) << L"Received message from " << pClientInfo->address() << ": " << message << L"\\r\\n";
74
75         std::vector<std::wstring> tokens;
76         int tokenCount = TokenizeMessage(message, &tokens);
77
78         CIICommandPtr pCommand = Create(tokens[0]);
79         if((pCommand != 0) && (tokenCount-1) >= pCommand->GetMinimumParameters()) 
80         {
81                 pCommand->Setup(tokens);
82                 executor_.begin_invoke([=]{pCommand->Execute();});
83         }
84         else {} //report error  
85 }
86
87 int CIIProtocolStrategy::TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector)
88 {
89         std::wstringstream currentToken;
90
91         for(unsigned int charIndex=0; charIndex<message.size(); ++charIndex) 
92         {
93                 if(message[charIndex] == TokenDelimiter) 
94                 {
95                         pTokenVector->push_back(currentToken.str());
96                         currentToken.str(L"");
97                         continue;
98                 }
99
100                 if(message[charIndex] == L'\"')
101                         currentToken << L"&quot;";
102                 else if(message[charIndex] == L'<')
103                         currentToken << L"&lt;";
104                 else if(message[charIndex] == L'>')
105                         currentToken << L"&gt;";
106                 else 
107                         currentToken << message[charIndex];
108         }
109
110         if(currentToken.str().size() > 0)
111                 pTokenVector->push_back(currentToken.str());    
112
113         return (int)pTokenVector->size();
114 }
115
116 /************
117 // Examples (<X> = ASCIICHAR X)
118
119 I\25\3\VII\\                                                                    s�tter outputtype till 'vii'
120 I\25\4\1\\                                                                              enablar framebuffer (ignore this)
121
122 M\C/SVTNEWS\\                                                                   pekar ut vilken grafisk profil som skall anv�ndas
123
124 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
125
126 T\7\4009.VII\A\\                                                                l�gger ut skylt 4009
127
128 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)
129
130 V\5\3\1\1\namn.tga\1\\                                                  l�gger ut bilden namn.tga
131 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.
132
133 *************/
134
135 /**********************
136 New Commands to support the Netupe automation system
137 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
138 Y\<27>\\                                                                                        Stop. H�r kommer ett lagerID ocks� att skickas med (<27> = ESC)
139 Y\<254>\\                                                                                       Clear Canvas. H�r kommer ett lagerID ocks� att skickas med, utan det skall allt t�mmas
140 Y\<213><243>\\                                                                          Play. H�r kommer ett lagerID ocks� att skickas med
141
142 **********************/
143 CIICommandPtr CIIProtocolStrategy::Create(const std::wstring& name)
144 {
145         switch(name[0])
146         {
147                 case L'M': return std::make_shared<MediaCommand>(this);
148                 case L'W': return std::make_shared<WriteCommand>(this);
149                 case L'T': return std::make_shared<ImagestoreCommand>(this);
150                 case L'V': return std::make_shared<MiscellaneousCommand>(this);
151                 case L'Y': return std::make_shared<KeydataCommand>(this);
152                 default:                return nullptr;
153         }
154 }
155
156 void CIIProtocolStrategy::WriteTemplateData(const std::wstring& templateName, const std::wstring& titleName, const std::wstring& xmlData) 
157 {
158         std::wstring fullTemplateFilename = templateName;
159
160         if (!currentProfile_.empty())
161                 fullTemplateFilename = currentProfile_ + L"/" + templateName;
162
163         core::diagnostics::scoped_call_context save;
164         core::diagnostics::call_context::for_thread().video_channel = 1;
165         core::diagnostics::call_context::for_thread().layer = 0;
166         auto producer = cg_registry_->create_producer(get_dependencies(), fullTemplateFilename);
167
168         if (producer == core::frame_producer::empty())
169         {
170                 CASPAR_LOG(error) << "Failed to save instance of " << templateName << L" as " << titleName << L", template " << fullTemplateFilename << L"not found";
171                 return;
172         }
173
174         cg_registry_->get_proxy(producer)->add(1, fullTemplateFilename, true, L"", xmlData);
175
176         CASPAR_LOG(info) << "Saved an instance of " << templateName << L" as " << titleName ;
177
178         PutPreparedTemplate(titleName, spl::shared_ptr<core::frame_producer>(std::move(producer)));
179         
180 }
181
182 void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)
183 {
184         try
185         {
186                 pChannel_->stage().load(0, GetPreparedTemplate(titleName));
187                 pChannel_->stage().play(0);
188
189                 CASPAR_LOG(info) << L"Displayed title " << titleName ;
190         }
191         catch(caspar_exception&)
192         {
193                 CASPAR_LOG(error) << L"Failed to display title " << titleName;
194         }
195 }
196
197 void CIIProtocolStrategy::DisplayMediaFile(const std::wstring& filename) 
198 {
199         transition_info transition;
200         transition.type = transition_type::mix;
201         transition.duration = 12;
202
203         core::diagnostics::scoped_call_context save;
204         core::diagnostics::call_context::for_thread().video_channel = 1;
205         core::diagnostics::call_context::for_thread().layer = 0;
206
207         auto pFP = get_producer_registry()->create_producer(get_dependencies(), filename);
208         auto pTransition = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transition);
209
210         try
211         {
212                 pChannel_->stage().load(0, pTransition);
213         }
214         catch(...)
215         {
216                 CASPAR_LOG_CURRENT_EXCEPTION();
217                 CASPAR_LOG(error) << L"Failed to display " << filename ;
218                 return;
219         }
220
221         pChannel_->stage().play(0);
222
223         CASPAR_LOG(info) << L"Displayed " << filename;
224 }
225
226 spl::shared_ptr<core::frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)
227 {
228         spl::shared_ptr<core::frame_producer> result(frame_producer::empty());
229
230         TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
231         if(it != titles_.end()) {
232                 CASPAR_LOG(info) << L"Found title with name " << it->titleName;
233                 result = (*it).pframe_producer;
234         }
235         else 
236                 CASPAR_LOG(error) << L"Could not find title with name " << titleName;
237
238         return result;
239 }
240
241 void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, const spl::shared_ptr<core::frame_producer>& pFP)
242 {
243         CASPAR_LOG(info) << L"Saved title with name " << titleName;
244
245         TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);
246         if(it != titles_.end()) {
247                 titles_.remove((*it));
248         }
249
250         titles_.push_front(TitleHolder(titleName, pFP));
251
252         if(titles_.size() >= 6)
253                 titles_.resize(5);
254 }
255
256 bool operator==(const CIIProtocolStrategy::TitleHolder& lhs, const std::wstring& rhs) 
257 {
258         return lhs.titleName == rhs;
259 }
260
261 bool operator==(const std::wstring& lhs, const CIIProtocolStrategy::TitleHolder& rhs)
262 {
263         return lhs == rhs.titleName;
264 }
265
266 }}}