2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
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.
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.
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/>.
19 * Author: Helge Norberg, helge.norberg@svt.se
22 #include "../StdAfx.h"
26 #include "frame_producer.h"
28 #include "../video_channel.h"
29 #include "../diagnostics/call_context.h"
31 #include <common/env.h>
32 #include <common/os/filesystem.h>
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>
43 namespace caspar { namespace core {
45 const spl::shared_ptr<cg_proxy>& cg_proxy::empty()
47 class empty_proxy : public cg_proxy
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"; }
60 static spl::shared_ptr<cg_proxy> instance = spl::make_shared<empty_proxy>();
64 using namespace boost::multi_index;
66 struct cg_producer_registry::impl
72 meta_info_extractor info_extractor;
73 cg_proxy_factory proxy_factory;
74 cg_producer_factory producer_factory;
75 bool reusable_producer_instance;
78 mutable boost::mutex mutex_;
79 std::map<std::wstring, record> records_by_extension_;
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)
89 boost::lock_guard<boost::mutex> lock(mutex_);
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
100 for (auto& extension : file_extensions)
102 records_by_extension_.insert(std::make_pair(extension, rec));
106 spl::shared_ptr<frame_producer> create_producer(
107 const frame_producer_dependencies& dependencies,
108 const std::wstring& filename) const
110 auto found = find_record(filename);
113 return frame_producer::empty();
115 return found->producer_factory(dependencies, filename);
118 spl::shared_ptr<cg_proxy> get_proxy(const spl::shared_ptr<frame_producer>& producer) const
120 auto producer_name = producer->name();
122 boost::lock_guard<boost::mutex> lock(mutex_);
124 for (auto& elem : records_by_extension_)
126 if (elem.second.name == producer_name)
127 return elem.second.proxy_factory(producer);
130 return cg_proxy::empty();
133 spl::shared_ptr<cg_proxy> get_proxy(
134 const spl::shared_ptr<video_channel>& video_channel,
135 int render_layer) const
137 auto producer = spl::make_shared_ptr(video_channel->stage().foreground(render_layer).get());
139 return get_proxy(producer);
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,
146 const std::wstring& filename) const
148 using namespace boost::filesystem;
150 auto found = find_record(filename);
153 return cg_proxy::empty();
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;
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;
165 producer = found->producer_factory(dependencies, filename);
166 video_channel->stage().load(render_layer, producer);
167 video_channel->stage().play(render_layer);
170 return found->proxy_factory(producer);
173 std::string read_meta_info(const std::wstring& filename) const
175 using namespace boost::filesystem;
177 auto basepath = path(env::template_folder()) / path(filename);
179 boost::lock_guard<boost::mutex> lock(mutex_);
181 for (auto& rec : records_by_extension_)
183 auto p = path(basepath.wstring() + rec.first);
184 auto found = find_case_insensitive(p.wstring());
187 return rec.second.info_extractor(*found);
190 CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"No meta info extractor for " + filename));
193 bool is_cg_extension(const std::wstring& extension) const
195 boost::lock_guard<boost::mutex> lock(mutex_);
197 return records_by_extension_.find(extension) != records_by_extension_.end();
200 std::wstring get_cg_producer_name(const std::wstring& filename) const
202 auto record = find_record(filename);
205 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(filename + L" is not a cg template."));
210 boost::optional<record> find_record(const std::wstring& filename) const
212 using namespace boost::filesystem;
214 auto basepath = path(env::template_folder()) / path(filename);
216 boost::lock_guard<boost::mutex> lock(mutex_);
218 for (auto& rec : records_by_extension_)
220 auto p = path(basepath.wstring() + rec.first);
222 if (find_case_insensitive(p.wstring()))
230 cg_producer_registry::cg_producer_registry() : impl_(new impl) { }
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)
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);
249 spl::shared_ptr<frame_producer> cg_producer_registry::create_producer(
250 const frame_producer_dependencies& dependencies,
251 const std::wstring& filename) const
253 return impl_->create_producer(dependencies, filename);
256 spl::shared_ptr<cg_proxy> cg_producer_registry::get_proxy(
257 const spl::shared_ptr<frame_producer>& producer) const
259 return impl_->get_proxy(producer);
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
266 return impl_->get_proxy(video_channel, render_layer);
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,
273 const std::wstring& filename) const
275 return impl_->get_or_create_proxy(video_channel, dependencies, render_layer, filename);
278 std::string cg_producer_registry::read_meta_info(const std::wstring& filename) const
280 return impl_->read_meta_info(filename);
283 bool cg_producer_registry::is_cg_extension(const std::wstring& extension) const
285 return impl_->is_cg_extension(extension);
288 std::wstring cg_producer_registry::get_cg_producer_name(const std::wstring& filename) const
290 return impl_->get_cg_producer_name(filename);