]> git.sesse.net Git - casparcg/blob - core/producer/cg_proxy.cpp
* Added Linux support for html producer
[casparcg] / core / producer / cg_proxy.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: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #include "../StdAfx.h"
23
24 #include "cg_proxy.h"
25
26 #include "frame_producer.h"
27 #include "stage.h"
28 #include "../video_channel.h"
29 #include "../diagnostics/call_context.h"
30
31 #include <common/env.h>
32 #include <common/os/filesystem.h>
33
34 #include <boost/thread/mutex.hpp>
35 #include <boost/thread/lock_guard.hpp>
36 #include <boost/filesystem.hpp>
37 #include <boost/algorithm/string/predicate.hpp>
38 #include <boost/optional.hpp>
39
40 #include <future>
41 #include <vector>
42
43 namespace caspar { namespace core {
44
45 const spl::shared_ptr<cg_proxy>& cg_proxy::empty()
46 {
47         class empty_proxy : public cg_proxy
48         {
49                 void add(int, const std::wstring&, bool, const std::wstring&, const std::wstring&) override {}
50                 void remove(int) override {}
51                 void play(int) override {}
52                 void stop(int, unsigned int) override {}
53                 void next(int) override {}
54                 void update(int, const std::wstring&) override {}
55                 std::wstring invoke(int, const std::wstring&) override { return L""; }
56                 std::wstring description(int) override { return L"empty cg producer"; }
57                 std::wstring template_host_info() override { return L"empty cg producer"; }
58         };
59
60         static spl::shared_ptr<cg_proxy> instance = spl::make_shared<empty_proxy>();
61         return instance;
62 }
63
64 using namespace boost::multi_index;
65
66 struct cg_producer_registry::impl
67 {
68 private:
69         struct record
70         {
71                 std::wstring                    name;
72                 std::set<std::wstring>  file_extensions;
73                 meta_info_extractor             info_extractor;
74                 cg_proxy_factory                proxy_factory;
75                 cg_producer_factory             producer_factory;
76                 bool                                    reusable_producer_instance;
77         };
78
79         struct name {};
80         struct extension {};
81
82         mutable boost::mutex    mutex_;
83         std::vector<record>             records_;
84 public:
85         void register_cg_producer(
86                         std::wstring cg_producer_name,
87                         std::set<std::wstring> file_extensions,
88                         meta_info_extractor info_extractor,
89                         cg_proxy_factory proxy_factory,
90                         cg_producer_factory producer_factory,
91                         bool reusable_producer_instance)
92         {
93                 boost::lock_guard<boost::mutex> lock(mutex_);
94
95                 records_.push_back(
96                 {
97                         std::move(cg_producer_name),
98                         std::move(file_extensions),
99                         std::move(info_extractor),
100                         std::move(proxy_factory),
101                         std::move(producer_factory),
102                         reusable_producer_instance
103                 });
104         }
105
106         spl::shared_ptr<frame_producer> create_producer(
107                         const spl::shared_ptr<video_channel>& video_channel,
108                         const std::wstring& filename) const
109         {
110                 auto found = find_record(filename);
111
112                 if (!found)
113                         return frame_producer::empty();
114
115                 return found->producer_factory(
116                                 video_channel->frame_factory(),
117                                 video_channel->video_format_desc(),
118                                 filename);
119         }
120
121         spl::shared_ptr<cg_proxy> get_proxy(const spl::shared_ptr<frame_producer>& producer) const
122         {
123                 auto producer_name = producer->name();
124
125                 boost::lock_guard<boost::mutex> lock(mutex_);
126
127                 for (auto& elem : records_)
128                 {
129                         if (elem.name == producer_name)
130                                 return elem.proxy_factory(producer);
131                 }
132
133                 return cg_proxy::empty();
134         }
135
136         spl::shared_ptr<cg_proxy> get_proxy(
137                         const spl::shared_ptr<class video_channel>& video_channel,
138                         int render_layer) const
139         {
140                 auto producer = spl::make_shared_ptr(video_channel->stage().foreground(render_layer).get());
141
142                 return get_proxy(producer);
143         }
144
145         spl::shared_ptr<cg_proxy> get_or_create_proxy(
146                         const spl::shared_ptr<class video_channel>& video_channel,
147                         int render_layer,
148                         const std::wstring& filename) const
149         {
150                 using namespace boost::filesystem;
151
152                 auto found = find_record(filename);
153
154                 if (!found)
155                         return cg_proxy::empty();
156
157                 auto producer = spl::make_shared_ptr(video_channel->stage().foreground(render_layer).get());
158                 auto current_producer_name = producer->name();
159                 bool create_new = current_producer_name != found->name || !found->reusable_producer_instance;
160
161                 if (create_new)
162                 {
163                         diagnostics::scoped_call_context save;
164                         diagnostics::call_context::for_thread().video_channel = video_channel->index();
165                         diagnostics::call_context::for_thread().layer = render_layer;
166
167                         producer = found->producer_factory(
168                                         video_channel->frame_factory(),
169                                         video_channel->video_format_desc(),
170                                         filename);
171                         video_channel->stage().load(render_layer, producer);
172                         video_channel->stage().play(render_layer);
173                 }
174
175                 return found->proxy_factory(producer);
176         }
177
178         std::string read_meta_info(const std::wstring& filename) const
179         {
180                 using namespace boost::filesystem;
181
182                 auto basepath = path(env::template_folder()) / path(filename);
183
184                 boost::lock_guard<boost::mutex> lock(mutex_);
185
186                 for (auto& rec : records_)
187                 {
188                         for (auto& file_extension : rec.file_extensions)
189                         {
190                                 auto p = path(basepath.wstring() + file_extension);
191
192                                 if (exists(p))
193                                 {
194                                         return rec.info_extractor(filename);
195                                 }
196                         }
197                 }
198
199                 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(L"No meta info extractor for " + filename));
200         }
201
202         bool is_cg_extension(const std::wstring& extension) const
203         {
204                 boost::lock_guard<boost::mutex> lock(mutex_);
205
206                 for (auto& rec : records_)
207                 {
208                         for (auto& file_extension : rec.file_extensions)
209                         {
210                                 if (boost::algorithm::iequals(file_extension, extension))
211                                         return true;
212                         }
213                 }
214
215                 return false;
216         }
217 private:
218         boost::optional<record> find_record(const std::wstring& filename) const
219         {
220                 using namespace boost::filesystem;
221
222                 auto basepath = path(env::template_folder()) / path(filename);
223
224                 boost::lock_guard<boost::mutex> lock(mutex_);
225
226                 for (auto& rec : records_)
227                 {
228                         for (auto& file_extension : rec.file_extensions)
229                         {
230                                 auto p = path(basepath.wstring() + file_extension);
231
232                                 if (find_case_insensitive(p.wstring()))
233                                         return rec;
234                         }
235                 }
236
237                 return boost::none;
238         }
239 };
240
241 cg_producer_registry::cg_producer_registry() : impl_(new impl) { }
242
243 void cg_producer_registry::register_cg_producer(
244                 std::wstring cg_producer_name,
245                 std::set<std::wstring> file_extensions,
246                 meta_info_extractor info_extractor,
247                 cg_proxy_factory proxy_factory,
248                 cg_producer_factory producer_factory,
249                 bool reusable_producer_instance)
250 {
251         impl_->register_cg_producer(
252                         std::move(cg_producer_name),
253                         std::move(file_extensions),
254                         std::move(info_extractor),
255                         std::move(proxy_factory),
256                         std::move(producer_factory),
257                         reusable_producer_instance);
258 }
259
260 spl::shared_ptr<frame_producer> cg_producer_registry::create_producer(
261                 const spl::shared_ptr<video_channel>& video_channel,
262                 const std::wstring& filename) const
263 {
264         return impl_->create_producer(video_channel, filename);
265 }
266
267 spl::shared_ptr<cg_proxy> cg_producer_registry::get_proxy(
268                 const spl::shared_ptr<frame_producer>& producer) const
269 {
270         return impl_->get_proxy(producer);
271 }
272
273 spl::shared_ptr<cg_proxy> cg_producer_registry::get_proxy(
274                 const spl::shared_ptr<video_channel>& video_channel,
275                 int render_layer) const
276 {
277         return impl_->get_proxy(video_channel, render_layer);
278 }
279
280 spl::shared_ptr<cg_proxy> cg_producer_registry::get_or_create_proxy(
281                 const spl::shared_ptr<video_channel>& video_channel,
282                 int render_layer,
283                 const std::wstring& filename) const
284 {
285         return impl_->get_or_create_proxy(video_channel, render_layer, filename);
286 }
287
288 std::string cg_producer_registry::read_meta_info(const std::wstring& filename) const
289 {
290         return impl_->read_meta_info(filename);
291 }
292
293 bool cg_producer_registry::is_cg_extension(const std::wstring& extension) const
294 {
295         return impl_->is_cg_extension(extension);
296 }
297
298 }}