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