]> git.sesse.net Git - casparcg/blob - core/producer/cg_proxy.cpp
74a1318e83112232f24990856b8773a04755e3cd
[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 <map>
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                 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         mutable boost::mutex                    mutex_;
79         std::map<std::wstring, record>  records_by_extension_;
80 public:
81         void register_cg_producer(
82                         std::wstring cg_producer_name,
83                         std::set<std::wstring> file_extensions,
84                         meta_info_extractor info_extractor,
85                         cg_proxy_factory proxy_factory,
86                         cg_producer_factory producer_factory,
87                         bool reusable_producer_instance)
88         {
89                 boost::lock_guard<boost::mutex> lock(mutex_);
90
91                 record rec
92                 {
93                         std::move(cg_producer_name),
94                         std::move(info_extractor),
95                         std::move(proxy_factory),
96                         std::move(producer_factory),
97                         reusable_producer_instance
98                 };
99
100                 for (auto& extension : file_extensions)
101                 {
102                         records_by_extension_.insert(std::make_pair(extension, rec));
103                 }
104         }
105
106         spl::shared_ptr<frame_producer> create_producer(
107                         const frame_producer_dependencies& dependencies,
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(dependencies, filename);
116         }
117
118         spl::shared_ptr<cg_proxy> get_proxy(const spl::shared_ptr<frame_producer>& producer) const
119         {
120                 auto producer_name = producer->name();
121
122                 boost::lock_guard<boost::mutex> lock(mutex_);
123
124                 for (auto& elem : records_by_extension_)
125                 {
126                         if (elem.second.name == producer_name)
127                                 return elem.second.proxy_factory(producer);
128                 }
129
130                 return cg_proxy::empty();
131         }
132
133         spl::shared_ptr<cg_proxy> get_proxy(
134                         const spl::shared_ptr<video_channel>& video_channel,
135                         int render_layer) const
136         {
137                 auto producer = spl::make_shared_ptr(video_channel->stage().foreground(render_layer).get());
138
139                 return get_proxy(producer);
140         }
141
142         spl::shared_ptr<cg_proxy> get_or_create_proxy(
143                         const spl::shared_ptr<video_channel>& video_channel,
144                         const frame_producer_dependencies& dependencies,
145                         int render_layer,
146                         const std::wstring& filename) const
147         {
148                 using namespace boost::filesystem;
149
150                 auto found = find_record(filename);
151
152                 if (!found)
153                         return cg_proxy::empty();
154
155                 auto producer = spl::make_shared_ptr(video_channel->stage().foreground(render_layer).get());
156                 auto current_producer_name = producer->name();
157                 bool create_new = current_producer_name != found->name || !found->reusable_producer_instance;
158
159                 if (create_new)
160                 {
161                         diagnostics::scoped_call_context save;
162                         diagnostics::call_context::for_thread().video_channel = video_channel->index();
163                         diagnostics::call_context::for_thread().layer = render_layer;
164
165                         producer = found->producer_factory(dependencies, filename);
166                         video_channel->stage().load(render_layer, producer);
167                         video_channel->stage().play(render_layer);
168                 }
169
170                 return found->proxy_factory(producer);
171         }
172
173         std::string read_meta_info(const std::wstring& filename) const
174         {
175                 using namespace boost::filesystem;
176
177                 auto basepath = path(env::template_folder()) / path(filename);
178
179                 boost::lock_guard<boost::mutex> lock(mutex_);
180
181                 for (auto& rec : records_by_extension_)
182                 {
183                         auto p = path(basepath.wstring() + rec.first);
184                         auto found = find_case_insensitive(p.wstring());
185
186                         if (found)
187                                 return rec.second.info_extractor(*found);
188                 }
189
190                 CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"No meta info extractor for " + filename));
191         }
192
193         bool is_cg_extension(const std::wstring& extension) const
194         {
195                 boost::lock_guard<boost::mutex> lock(mutex_);
196
197                 return records_by_extension_.find(extension) != records_by_extension_.end();
198         }
199
200         std::wstring get_cg_producer_name(const std::wstring& filename) const
201         {
202                 auto record = find_record(filename);
203
204                 if (!record)
205                         CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(filename + L" is not a cg template."));
206
207                 return record->name;
208         }
209 private:
210         boost::optional<record> find_record(const std::wstring& filename) const
211         {
212                 using namespace boost::filesystem;
213
214                 auto basepath = path(env::template_folder()) / path(filename);
215
216                 boost::lock_guard<boost::mutex> lock(mutex_);
217
218                 for (auto& rec : records_by_extension_)
219                 {
220                         auto p = path(basepath.wstring() + rec.first);
221
222                         if (find_case_insensitive(p.wstring()))
223                                 return rec.second;
224                 }
225
226                 return boost::none;
227         }
228 };
229
230 cg_producer_registry::cg_producer_registry() : impl_(new impl) { }
231
232 void cg_producer_registry::register_cg_producer(
233                 std::wstring cg_producer_name,
234                 std::set<std::wstring> file_extensions,
235                 meta_info_extractor info_extractor,
236                 cg_proxy_factory proxy_factory,
237                 cg_producer_factory producer_factory,
238                 bool reusable_producer_instance)
239 {
240         impl_->register_cg_producer(
241                         std::move(cg_producer_name),
242                         std::move(file_extensions),
243                         std::move(info_extractor),
244                         std::move(proxy_factory),
245                         std::move(producer_factory),
246                         reusable_producer_instance);
247 }
248
249 spl::shared_ptr<frame_producer> cg_producer_registry::create_producer(
250                 const frame_producer_dependencies& dependencies,
251                 const std::wstring& filename) const
252 {
253         return impl_->create_producer(dependencies, filename);
254 }
255
256 spl::shared_ptr<cg_proxy> cg_producer_registry::get_proxy(
257                 const spl::shared_ptr<frame_producer>& producer) const
258 {
259         return impl_->get_proxy(producer);
260 }
261
262 spl::shared_ptr<cg_proxy> cg_producer_registry::get_proxy(
263                 const spl::shared_ptr<video_channel>& video_channel,
264                 int render_layer) const
265 {
266         return impl_->get_proxy(video_channel, render_layer);
267 }
268
269 spl::shared_ptr<cg_proxy> cg_producer_registry::get_or_create_proxy(
270                 const spl::shared_ptr<video_channel>& video_channel,
271                 const frame_producer_dependencies& dependencies,
272                 int render_layer,
273                 const std::wstring& filename) const
274 {
275         return impl_->get_or_create_proxy(video_channel, dependencies, render_layer, filename);
276 }
277
278 std::string cg_producer_registry::read_meta_info(const std::wstring& filename) const
279 {
280         return impl_->read_meta_info(filename);
281 }
282
283 bool cg_producer_registry::is_cg_extension(const std::wstring& extension) const
284 {
285         return impl_->is_cg_extension(extension);
286 }
287
288 std::wstring cg_producer_registry::get_cg_producer_name(const std::wstring& filename) const
289 {
290         return impl_->get_cg_producer_name(filename);
291 }
292
293 }}