* In order to support route:// without the same intrusive changes in AMCPCommandsImpl.cpp from 2.0, refactored so that every producer factory gets a list of channels.
* Refactored so that frame_factory and video_format_desc is now part of a type called frame_producer_dependencies. The list of channels needed by reroute producer was also added to this class. Future dependencies will not need a change in the signature of every producer factory.
* Fixed possible race condition in stage.cpp where std::map could be modified from multiple threads
consumer/frame_consumer.h
consumer/output.h
consumer/port.h
+ consumer/write_frame_consumer.h
diagnostics/call_context.h
diagnostics/osd_graph.h
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#pragma once
+
+#include "../fwd.h"
+
+#include <common/memory.h>
+
+#include <boost/noncopyable.hpp>
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace caspar { namespace core {
+
+struct write_frame_consumer : boost::noncopyable
+{
+ virtual ~write_frame_consumer() {}
+
+ virtual void send(const draw_frame& frame) = 0;
+ virtual std::wstring print() const = 0;
+ //virtual boost::property_tree::wptree info() const = 0;
+};
+
+}}
\ No newline at end of file
FORWARD2(caspar, core, class system_info_provider_repository);
FORWARD2(caspar, core, class cg_producer_registry);
FORWARD2(caspar, core, struct frame_transform);
-
+FORWARD2(caspar, core, struct write_frame_consumer);
+FORWARD2(caspar, core, struct frame_producer_dependencies);
}
spl::shared_ptr<frame_producer> create_producer(
- const spl::shared_ptr<video_channel>& video_channel,
+ const frame_producer_dependencies& dependencies,
const std::wstring& filename) const
{
auto found = find_record(filename);
if (!found)
return frame_producer::empty();
- return found->producer_factory(
- video_channel->frame_factory(),
- video_channel->video_format_desc(),
- filename);
+ return found->producer_factory(dependencies, filename);
}
spl::shared_ptr<cg_proxy> get_proxy(const spl::shared_ptr<frame_producer>& producer) const
spl::shared_ptr<cg_proxy> get_or_create_proxy(
const spl::shared_ptr<video_channel>& video_channel,
+ const frame_producer_dependencies& dependencies,
int render_layer,
const std::wstring& filename) const
{
diagnostics::call_context::for_thread().video_channel = video_channel->index();
diagnostics::call_context::for_thread().layer = render_layer;
- producer = found->producer_factory(
- video_channel->frame_factory(),
- video_channel->video_format_desc(),
- filename);
+ producer = found->producer_factory(dependencies, filename);
video_channel->stage().load(render_layer, producer);
video_channel->stage().play(render_layer);
}
}
spl::shared_ptr<frame_producer> cg_producer_registry::create_producer(
- const spl::shared_ptr<video_channel>& video_channel,
+ const frame_producer_dependencies& dependencies,
const std::wstring& filename) const
{
- return impl_->create_producer(video_channel, filename);
+ return impl_->create_producer(dependencies, filename);
}
spl::shared_ptr<cg_proxy> cg_producer_registry::get_proxy(
spl::shared_ptr<cg_proxy> cg_producer_registry::get_or_create_proxy(
const spl::shared_ptr<video_channel>& video_channel,
+ const frame_producer_dependencies& dependencies,
int render_layer,
const std::wstring& filename) const
{
- return impl_->get_or_create_proxy(video_channel, render_layer, filename);
+ return impl_->get_or_create_proxy(video_channel, dependencies, render_layer, filename);
}
std::string cg_producer_registry::read_meta_info(const std::wstring& filename) const
const spl::shared_ptr<frame_producer>& producer
)> cg_proxy_factory;
typedef std::function<spl::shared_ptr<frame_producer>(
- const spl::shared_ptr<frame_factory>& factory,
- const video_format_desc& format_desc,
+ const frame_producer_dependencies& dependencies,
const std::wstring& filename
)> cg_producer_factory;
typedef std::function<std::string(const std::wstring& filename)> meta_info_extractor;
bool reusable_producer_instance);
spl::shared_ptr<frame_producer> create_producer(
- const spl::shared_ptr<video_channel>& video_channel,
+ const frame_producer_dependencies& dependencies,
const std::wstring& filename) const;
spl::shared_ptr<cg_proxy> get_proxy(
const spl::shared_ptr<frame_producer>& producer) const;
int render_layer) const;
spl::shared_ptr<cg_proxy> get_or_create_proxy(
const spl::shared_ptr<video_channel>& video_channel,
+ const frame_producer_dependencies& dependencies,
int render_layer,
const std::wstring& filename) const;
std::string read_meta_info(const std::wstring& filename) const;
g_thumbnail_factories.push_back(factory);
}
+frame_producer_dependencies::frame_producer_dependencies(
+ const spl::shared_ptr<core::frame_factory>& frame_factory,
+ const std::vector<spl::shared_ptr<video_channel>>& channels,
+ const video_format_desc& format_desc)
+ : frame_factory(frame_factory)
+ , channels(channels)
+ , format_desc(format_desc)
+{
+}
+
constraints::constraints(double width, double height)
: width(width), height(height)
{
return spl::make_shared<destroy_producer_proxy>(std::move(producer));
}
-spl::shared_ptr<core::frame_producer> do_create_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params, const std::vector<producer_factory_t>& factories, bool throw_on_fail = false)
+spl::shared_ptr<core::frame_producer> do_create_producer(const frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params, const std::vector<producer_factory_t>& factories, bool throw_on_fail = false)
{
if(params.empty())
CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));
{
try
{
- producer = factory(my_frame_factory, format_desc, params);
+ producer = factory(dependencies, params);
}
catch(...)
{
});
if(producer == frame_producer::empty())
- producer = create_color_producer(my_frame_factory, params);
+ producer = create_color_producer(dependencies.frame_factory, params);
if (producer == frame_producer::empty())
- producer = create_freehand_producer(my_frame_factory, params);
+ producer = create_freehand_producer(dependencies.frame_factory, params);
if(producer == frame_producer::empty())
return producer;
return producer;
}
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::wstring& media_file)
+spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const frame_producer_dependencies& dependencies, const std::wstring& media_file)
{
std::vector<std::wstring> params;
params.push_back(media_file);
- auto producer = do_create_producer(my_frame_factory, format_desc, params, g_thumbnail_factories, true);
+ auto producer = do_create_producer(dependencies, params, g_thumbnail_factories, true);
auto key_producer = frame_producer::empty();
try // to find a key file.
if (params_copy.size() > 0)
{
params_copy[0] += L"_A";
- key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_thumbnail_factories, true);
+ key_producer = do_create_producer(dependencies, params_copy, g_thumbnail_factories, true);
if (key_producer == frame_producer::empty())
{
params_copy[0] += L"LPHA";
- key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_thumbnail_factories, true);
+ key_producer = do_create_producer(dependencies, params_copy, g_thumbnail_factories, true);
}
}
}
return producer;
}
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>& my_frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_producer(const frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
- auto producer = do_create_producer(my_frame_factory, format_desc, params, g_producer_factories);
+ auto producer = do_create_producer(dependencies, params, g_producer_factories);
auto key_producer = frame_producer::empty();
try // to find a key file.
if(params_copy.size() > 0)
{
params_copy[0] += L"_A";
- key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_producer_factories);
+ key_producer = do_create_producer(dependencies, params_copy, g_producer_factories);
if(key_producer == frame_producer::empty())
{
params_copy[0] += L"LPHA";
- key_producer = do_create_producer(my_frame_factory, format_desc, params_copy, g_producer_factories);
+ key_producer = do_create_producer(dependencies, params_copy, g_producer_factories);
}
}
}
}
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>& factory, const video_format_desc& format_desc, const std::wstring& params)
+spl::shared_ptr<core::frame_producer> create_producer(const frame_producer_dependencies& dependencies, const std::wstring& params)
{
std::wstringstream iss(params);
std::vector<std::wstring> tokens;
typedef std::istream_iterator<std::wstring, wchar_t, std::char_traits<wchar_t> > iterator;
std::copy(iterator(iss), iterator(), std::back_inserter(tokens));
- return create_producer(factory, format_desc, tokens);
+ return create_producer(dependencies, tokens);
}
}}
std::shared_ptr<impl> impl_;
};
-typedef std::function<spl::shared_ptr<core::frame_producer>(const spl::shared_ptr<class frame_factory>&, const video_format_desc& format_desc, const std::vector<std::wstring>&)> producer_factory_t;
+struct frame_producer_dependencies
+{
+ spl::shared_ptr<core::frame_factory> frame_factory;
+ std::vector<spl::shared_ptr<video_channel>> channels;
+ video_format_desc format_desc;
+
+ frame_producer_dependencies(
+ const spl::shared_ptr<core::frame_factory>& frame_factory,
+ const std::vector<spl::shared_ptr<video_channel>>& channels,
+ const video_format_desc& format_desc);
+};
+
+typedef std::function<spl::shared_ptr<core::frame_producer>(const frame_producer_dependencies&, const std::vector<std::wstring>&)> producer_factory_t;
void register_producer_factory(const producer_factory_t& factory); // Not thread-safe.
void register_thumbnail_producer_factory(const producer_factory_t& factory); // Not thread-safe.
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::wstring& params);
+spl::shared_ptr<core::frame_producer> create_producer(const frame_producer_dependencies&, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_producer(const frame_producer_dependencies&, const std::wstring& params);
spl::shared_ptr<core::frame_producer> create_destroy_proxy(spl::shared_ptr<core::frame_producer> producer);
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const spl::shared_ptr<frame_factory>&, const video_format_desc& format_desc, const std::wstring& media_file);
+spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const frame_producer_dependencies&, const std::wstring& media_file);
}}
return impl_->get_variables();
}
-spl::shared_ptr<core::frame_producer> create_dummy_scene_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
-{
- if (params.size() < 1 || !boost::iequals(params.at(0), L"[SCENE]"))
- return core::frame_producer::empty();
-
- auto scene = spl::make_shared<scene_producer>(format_desc.width, format_desc.height, format_desc);
-
- text::text_info text_info;
- text_info.font = L"ArialMT";
- text_info.size = 62;
- text_info.color.r = 1;
- text_info.color.g = 1;
- text_info.color.b = 1;
- text_info.color.a = 0.5;
- auto text_area = text_producer::create(frame_factory, 0, 0, L"a", text_info, 1280, 720, false);
-
- auto text_width = text_area->pixel_constraints().width;
- binding<double> padding(1.0);
- binding<double> panel_width = padding + text_width + padding;
- binding<double> panel_height = padding + text_area->pixel_constraints().height + padding;
-
- auto subscription = panel_width.on_change([&]
- {
- CASPAR_LOG(info) << "Panel width: " << panel_width.get();
- });
-
- padding.set(2);
-
- auto create_param = [](std::wstring elem) -> std::vector<std::wstring>
- {
- std::vector<std::wstring> result;
- result.push_back(elem);
- return result;
- };
-
- auto& car_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"car")), L"car");
- car_layer.adjustments.opacity.set(0.5);
- //car_layer.hidden = scene->frame() % 50 > 25 || !(scene->frame() < 1000);
- std::vector<std::wstring> sub_params;
- sub_params.push_back(L"[FREEHAND]");
- sub_params.push_back(L"640");
- sub_params.push_back(L"360");
- scene->create_layer(create_producer(frame_factory, format_desc, sub_params), 10, 10, L"freehand");
- sub_params.clear();
-
- auto& color_layer = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"RED")), 110, 10, L"color");
- color_layer.producer.get()->pixel_constraints().width.set(1000);
- color_layer.producer.get()->pixel_constraints().height.set(550);
-
- //scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"SP")), 50, 50);
-
- auto& upper_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_left")), L"upper_left");
- auto& upper_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/upper_right")), L"upper_right");
- auto& lower_left = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_left")), L"lower_left");
- auto& lower_right = scene->create_layer(create_producer(frame_factory, format_desc, create_param(L"scene/lower_right")), L"lower_right");
- auto& text_layer = scene->create_layer(text_area, L"text_area");
- upper_left.adjustments.opacity.bind(text_layer.adjustments.opacity);
- upper_right.adjustments.opacity.bind(text_layer.adjustments.opacity);
- lower_left.adjustments.opacity.bind(text_layer.adjustments.opacity);
- lower_right.adjustments.opacity.bind(text_layer.adjustments.opacity);
-
- /*
- binding<double> panel_x = (scene->frame()
- .as<double>()
- .transformed([](double v) { return std::sin(v / 20.0); })
- * 20.0
- + 40.0)
- .transformed([](double v) { return std::floor(v); }); // snap to pixels instead of subpixels
- */
- tweener tween(L"easeoutbounce");
- binding<double> panel_x(0.0);
-
- scene->add_keyframe(panel_x, -panel_width, 0);
- scene->add_keyframe(panel_x, 300.0, 50, L"easeinoutsine");
- scene->add_keyframe(panel_x, 300.0, 50 * 4);
- scene->add_keyframe(panel_x, 1000.0, 50 * 5, L"easeinoutsine");
- //panel_x = delay(panel_x, add_tween(panel_x, scene->frame(), 200.0, int64_t(50), L"linear"), scene->frame(), int64_t(100));
- /*binding<double> panel_x = when(scene->frame() < 50)
- .then(scene->frame().as<double>().transformed([tween](double t) { return tween(t, 0.0, 200, 50); }))
- .otherwise(200.0);*/
- //binding<double> panel_y = when(car_layer.hidden).then(500.0).otherwise(-panel_x + 300);
- binding<double> panel_y(500.0);
- scene->add_keyframe(panel_y, panel_y.get(), 50 * 4);
- scene->add_keyframe(panel_y, 720.0, 50 * 5, L"easeinexpo");
-
- scene->add_keyframe(text_layer.adjustments.opacity, 1.0, 100);
- scene->add_keyframe(text_layer.adjustments.opacity, 0.0, 125, L"linear");
- scene->add_keyframe(text_layer.adjustments.opacity, 1.0, 150, L"linear");
-
- upper_left.position.x = panel_x;
- upper_left.position.y = panel_y;
- upper_right.position.x = upper_left.position.x + upper_left.producer.get()->pixel_constraints().width + panel_width;
- upper_right.position.y = upper_left.position.y;
- lower_left.position.x = upper_left.position.x;
- lower_left.position.y = upper_left.position.y + upper_left.producer.get()->pixel_constraints().height + panel_height;
- lower_right.position.x = upper_right.position.x;
- lower_right.position.y = lower_left.position.y;
- text_layer.position.x = upper_left.position.x + upper_left.producer.get()->pixel_constraints().width + padding;
- text_layer.position.y = upper_left.position.y + upper_left.producer.get()->pixel_constraints().height + padding + text_area->current_bearing_y().as<double>();
-
- text_area->text().bind(scene->create_variable<std::wstring>(L"text", true));
-
- auto params2 = params;
- params2.erase(params2.begin());
-
- scene->call(params2);
-
- return scene;
-}
-
}}}
std::unique_ptr<impl> impl_;
};
-spl::shared_ptr<frame_producer> create_dummy_scene_producer(const spl::shared_ptr<frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params);
-
}}}
return spl::make_shared<core::scene::scene_cg_proxy>(producer);
},
[](
- const spl::shared_ptr<core::frame_factory>& factory,
- const core::video_format_desc& format_desc,
- const std::wstring& filename)
+ const core::frame_producer_dependencies& dependencies,
+ const std::wstring& filename)
{
- return create_xml_scene_producer(factory, format_desc, { filename });
+ return create_xml_scene_producer(dependencies, { filename });
},
false);
}
spl::shared_ptr<core::frame_producer> create_xml_scene_producer(
- const spl::shared_ptr<core::frame_factory>& frame_factory,
- const core::video_format_desc& format_desc,
+ const core::frame_producer_dependencies& dependencies,
const std::vector<std::wstring>& params)
{
if (params.empty())
int width = root.get<int>(L"scene.<xmlattr>.width");
int height = root.get<int>(L"scene.<xmlattr>.height");
- auto scene = spl::make_shared<scene_producer>(width, height, format_desc);
+ auto scene = spl::make_shared<scene_producer>(width, height, dependencies.format_desc);
for (auto elem : root.get_child(L"scene.variables"))
{
for (auto& elem : root.get_child(L"scene.layers"))
{
auto id = elem.second.get<std::wstring>(L"<xmlattr>.id");
- auto producer = create_producer(frame_factory, format_desc, elem.second.get<std::wstring>(L"producer"));
+ auto producer = create_producer(dependencies, elem.second.get<std::wstring>(L"producer"));
auto& layer = scene->create_layer(producer, 0, 0, id);
auto variable_prefix = L"layer." + id + L".";
namespace caspar { namespace core { namespace scene {
void init(module_dependencies dependencies);
-spl::shared_ptr<core::frame_producer> create_xml_scene_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_xml_scene_producer(const frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
}}}
#include "../frame/draw_frame.h"
#include "../frame/frame_factory.h"
#include "../interaction/interaction_aggregator.h"
+#include "../consumer/write_frame_consumer.h"
#include <common/executor.h>
#include <common/future.h>
struct stage::impl : public std::enable_shared_from_this<impl>
{
- spl::shared_ptr<diagnostics::graph> graph_;
- spl::shared_ptr<monitor::subject> monitor_subject_;
- //reactive::basic_subject<std::map<int, draw_frame>> frames_subject_;
- std::map<int, layer> layers_;
- std::map<int, tweened_transform> tweens_;
- interaction_aggregator aggregator_;
- executor executor_;
+ spl::shared_ptr<diagnostics::graph> graph_;
+ spl::shared_ptr<monitor::subject> monitor_subject_;
+ //reactive::basic_subject<std::map<int, draw_frame>> frames_subject_;
+ std::map<int, layer> layers_;
+ std::map<int, tweened_transform> tweens_;
+ interaction_aggregator aggregator_;
+ // map of layer -> map of tokens (src ref) -> layer_consumer
+ std::map<int, std::map<void*, spl::shared_ptr<write_frame_consumer>>> layer_consumers_;
+ executor executor_;
public:
impl(spl::shared_ptr<diagnostics::graph> graph)
: graph_(std::move(graph))
for (auto& layer : layers_)
{
- frames[layer.first] = draw_frame::empty();
+ // Prevent race conditions in parallel for each later
+ frames[layer.first] = draw_frame::empty();
+ tweens_[layer.first];
+ layer_consumers_[layer.first];
+
indices.push_back(layer.first);
}
{
auto& layer = layers_[index];
auto& tween = tweens_[index];
-
+ auto& consumers = layer_consumers_[index];
+
auto frame = layer.receive(format_desc);
+
+ if (!consumers.empty())
+ {
+ auto consumer_it = consumers | boost::adaptors::map_values;
+ tbb::parallel_for_each(consumer_it.begin(), consumer_it.end(), [&](decltype(*consumer_it.begin()) layer_consumer)
+ {
+ layer_consumer->send(frame);
+ });
+ }
+
auto frame1 = frame;
+
frame1.transform() *= tween.fetch_and_tick(1);
if(format_desc.field_mode != core::field_mode::progressive)
}, task_priority::high_priority);
}
}
-
+
+ void add_layer_consumer(void* token, int layer, const spl::shared_ptr<write_frame_consumer>& layer_consumer)
+ {
+ executor_.begin_invoke([=]
+ {
+ layer_consumers_[layer].insert(std::make_pair(token, layer_consumer));
+ }, task_priority::high_priority);
+ }
+
+ void remove_layer_consumer(void* token, int layer)
+ {
+ executor_.begin_invoke([=]
+ {
+ auto& layer_map = layer_consumers_[layer];
+ layer_map.erase(token);
+ if (layer_map.empty())
+ {
+ layer_consumers_.erase(layer);
+ }
+ }, task_priority::high_priority);
+ }
+
std::future<std::shared_ptr<frame_producer>> foreground(int index)
{
return executor_.begin_invoke([=]() -> std::shared_ptr<frame_producer>
std::future<void> stage::swap_layers(stage& other){ return impl_->swap_layers(other); }
std::future<void> stage::swap_layer(int index, int other_index){ return impl_->swap_layer(index, other_index); }
std::future<void> stage::swap_layer(int index, int other_index, stage& other){ return impl_->swap_layer(index, other_index, other); }
-std::future<std::shared_ptr<frame_producer>> stage::foreground(int index) { return impl_->foreground(index); }
+void stage::add_layer_consumer(void* token, int layer, const spl::shared_ptr<write_frame_consumer>& layer_consumer){ impl_->add_layer_consumer(token, layer, layer_consumer); }
+void stage::remove_layer_consumer(void* token, int layer){ impl_->remove_layer_consumer(token, layer); }std::future<std::shared_ptr<frame_producer>> stage::foreground(int index) { return impl_->foreground(index); }
std::future<std::shared_ptr<frame_producer>> stage::background(int index) { return impl_->background(index); }
std::future<boost::property_tree::wptree> stage::info() const{ return impl_->info(); }
std::future<boost::property_tree::wptree> stage::info(int index) const{ return impl_->info(index); }
#pragma once
-#include "frame_producer.h"
-
+#include "../fwd.h"
#include "../monitor/monitor.h"
#include "../interaction/interaction_sink.h"
{
stage(const stage&);
stage& operator=(const stage&);
-public:
+public:
// Static Members
std::future<void> swap_layer(int index, int other_index);
std::future<void> swap_layer(int index, int other_index, stage& other);
+ void add_layer_consumer(void* token, int layer, const spl::shared_ptr<write_frame_consumer>& layer_consumer);
+ void remove_layer_consumer(void* token, int layer);
+
monitor::subject& monitor_output();
// frame_observable
return spl::make_shared<text_producer>(frame_factory, x, y, str, text_info, parent_width, parent_height, standalone);
}
-spl::shared_ptr<frame_producer> create_text_producer(const spl::shared_ptr<frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<frame_producer> create_text_producer(const frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
if(params.size() < 2 || !boost::iequals(params.at(0), L"[text]"))
return core::frame_producer::empty();
bool standalone = get_param(L"STANDALONE", params, false);
- return text_producer::create(frame_factory, x, y, params.at(1), text_info, format_desc.width, format_desc.height, standalone);
+ return text_producer::create(
+ dependencies.frame_factory,
+ x, y,
+ params.at(1),
+ text_info,
+ dependencies.format_desc.width, dependencies.format_desc.height,
+ standalone);
}
}}
spl::unique_ptr<impl> impl_;
};
-spl::shared_ptr<frame_producer> create_text_producer(const spl::shared_ptr<frame_factory>& frame_factory, const video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<frame_producer> create_text_producer(const frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
}}
try
{
- producer = create_thumbnail_producer(image_mixer_, format_desc_, media_file);
+ producer = create_thumbnail_producer(
+ frame_producer_dependencies(image_mixer_, { }, format_desc_),
+ media_file);
}
catch (const boost::thread_interrupted&)
{
#include <tbb/spin_mutex.h>
#include <boost/property_tree/ptree.hpp>
+#include <boost/lexical_cast.hpp>
#include <string>
#include <core/frame/draw_frame.h>
#include <core/frame/frame_transform.h>
#include <core/frame/frame_factory.h>
+#include <core/producer/frame_producer.h>
#include <core/monitor/monitor.h>
#include <core/mixer/audio/audio_mixer.h>
}
};
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& out_format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
if(params.empty() || !boost::iequals(params.at(0), "decklink"))
return core::frame_producer::empty();
auto in_format_desc = core::video_format_desc(get_param(L"FORMAT", params, L"INVALID"));
if(in_format_desc.format == core::video_format::invalid)
- in_format_desc = out_format_desc;
+ in_format_desc = dependencies.format_desc;
- return create_destroy_proxy(spl::make_shared<decklink_producer_proxy>(in_format_desc, frame_factory, out_format_desc, device_index, filter_str, length));
+ return create_destroy_proxy(spl::make_shared<decklink_producer_proxy>(in_format_desc, dependencies.frame_factory, dependencies.format_desc, device_index, filter_str, length));
}
}}
#pragma once
-#include <core/producer/frame_producer.h>
+#include <core/fwd.h>
#include <string>
#include <vector>
namespace caspar { namespace decklink {
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
}}
}
};
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
auto filename = probe_stem(env::media_folder() + L"/" + params.at(0));
auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
auto filter_str = get_param(L"FILTER", params, L"");
- return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(frame_factory, format_desc, filename, filter_str, loop, start, length)));
+ return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(dependencies.frame_factory, dependencies.format_desc, filename, filter_str, loop, start, length)));
}
}}
#include <common/memory.h>
#include <core/fwd.h>
-#include <core/video_format.h>
#include <string>
#include <vector>
namespace caspar { namespace ffmpeg {
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
}}
\ No newline at end of file
};
spl::shared_ptr<core::frame_producer> create_ct_producer(
- const spl::shared_ptr<core::frame_factory> frame_factory,
- const core::video_format_desc& format_desc,
+ const core::frame_producer_dependencies& dependencies,
const std::vector<std::wstring>& params)
{
if (params.empty() || !boost::filesystem::exists(get_absolute(env::media_folder(), params.at(0)) + L".ct"))
return core::frame_producer::empty();
- auto flash_producer = flash::create_producer(frame_factory, format_desc, {});
+ auto flash_producer = flash::create_producer(dependencies, {});
auto producer = flash_producer;
flash_cg_proxy(producer, env::media_folder()).add(0, params.at(0), true, L"", L"");
{
return spl::make_shared<flash_cg_proxy>(producer);
},
- [](const spl::shared_ptr<core::frame_factory>& ff, const core::video_format_desc& f, const std::wstring&)
+ [](const core::frame_producer_dependencies& dependencies, const std::wstring&)
{
- return flash::create_producer(ff, f, { });
+ return flash::create_producer(dependencies, { });
},
true
);
#include <core/frame/draw_frame.h>
#include <core/frame/frame_factory.h>
#include <core/frame/pixel_format.h>
+#include <core/producer/frame_producer.h>
#include <core/monitor/monitor.h>
#include <common/env.h>
}
};
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
- auto template_host = get_template_host(format_desc);
+ auto template_host = get_template_host(dependencies.format_desc);
auto filename = env::template_folder() + L"\\" + template_host.filename;
if(!boost::filesystem::exists(filename))
CASPAR_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(u8(filename)));
- return create_destroy_proxy(spl::make_shared<flash_producer>(frame_factory, format_desc, filename, template_host.width, template_host.height));
+ return create_destroy_proxy(spl::make_shared<flash_producer>(dependencies.frame_factory, dependencies.format_desc, filename, template_host.width, template_host.height));
}
-spl::shared_ptr<core::frame_producer> create_swf_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_swf_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
auto filename = env::media_folder() + L"\\" + params.at(0) + L".swf";
swf_t::header_t header(filename);
return create_destroy_proxy(
- spl::make_shared<flash_producer>(frame_factory, format_desc, filename, header.frame_width, header.frame_height));
+ spl::make_shared<flash_producer>(dependencies.frame_factory, dependencies.format_desc, filename, header.frame_width, header.frame_height));
}
std::wstring find_template(const std::wstring& template_name)
#pragma once
-#include <core/producer/frame_producer.h>
+#include <core/fwd.h>
#include <common/memory.h>
namespace caspar { namespace flash {
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_producer> create_swf_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_swf_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
std::wstring find_template(const std::wstring& templateName);
{
return spl::make_shared<html_cg_proxy>(producer);
},
- [](const spl::shared_ptr<core::frame_factory>& ff, const core::video_format_desc& f, const std::wstring& filename)
+ [](const core::frame_producer_dependencies& dependencies, const std::wstring& filename)
{
- return html::create_producer(ff, f, { filename });
+ return html::create_producer(dependencies, { filename });
},
false
);
class html_producer
: public core::frame_producer_base
{
- core::monitor::subject monitor_subject_;
- const std::wstring url_;
- core::constraints constraints_;
+ core::monitor::subject monitor_subject_;
+ const std::wstring url_;
+ core::constraints constraints_;
- CefRefPtr<html_client> client_;
+ CefRefPtr<html_client> client_;
public:
html_producer(
};
spl::shared_ptr<core::frame_producer> create_producer(
- const spl::shared_ptr<core::frame_factory>& frame_factory,
- const core::video_format_desc& format_desc,
+ const core::frame_producer_dependencies& dependencies,
const std::vector<std::wstring>& params)
{
const auto filename = env::template_folder() + params.at(0) + L".html";
return core::frame_producer::empty();
return core::create_destroy_proxy(spl::make_shared<html_producer>(
- frame_factory,
- format_desc,
+ dependencies.frame_factory,
+ dependencies.format_desc,
url));
}
}
namespace caspar { namespace html {
spl::shared_ptr<core::frame_producer> create_producer(
- const spl::shared_ptr<core::frame_factory>& frame_factory,
- const core::video_format_desc& format_desc,
+ const core::frame_producer_dependencies& dependencies,
const std::vector<std::wstring>& params);
}}
\ No newline at end of file
}
};
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
static const auto extensions = {
L".png",
for (auto& file : files)
{
- auto frame = load_image(frame_factory, file);
+ auto frame = load_image(dependencies.frame_factory, file);
if (width == -1)
{
auto png_data = from_base64(std::string(params.at(1).begin(), params.at(1).end()));
- return spl::make_shared<image_producer>(frame_factory, png_data.data(), png_data.size());
+ return spl::make_shared<image_producer>(dependencies.frame_factory, png_data.data(), png_data.size());
}
std::wstring filename = env::media_folder() + params.at(0);
if(ext == extensions.end())
return core::frame_producer::empty();
- return spl::make_shared<image_producer>(frame_factory, *caspar::find_case_insensitive(filename + *ext));
+ return spl::make_shared<image_producer>(dependencies.frame_factory, *caspar::find_case_insensitive(filename + *ext));
}
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
- return caspar::image::create_producer(frame_factory, format_desc, params);
+ return caspar::image::create_producer(dependencies, params);
}
}}
namespace caspar { namespace image {
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
}}
\ No newline at end of file
}
};
-spl::shared_ptr<core::frame_producer> create_scroll_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_scroll_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
static const auto extensions = {
L".png",
bool progressive = contains_param(L"PROGRESSIVE", params);
return core::create_destroy_proxy(spl::make_shared<image_scroll_producer>(
- frame_factory,
- format_desc,
+ dependencies.frame_factory,
+ dependencies.format_desc,
*caspar::find_case_insensitive(filename + *ext),
-speed,
-duration,
namespace caspar { namespace image {
-spl::shared_ptr<core::frame_producer> create_scroll_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_producer> create_scroll_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params);
}}
\ No newline at end of file
}
}
-spl::shared_ptr<core::frame_producer> create_psd_scene_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_producer> create_psd_scene_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
std::wstring filename = env::template_folder() + params.at(0) + L".psd";
auto found_file = find_case_insensitive(filename);
psd_document doc;
doc.parse(*found_file);
- spl::shared_ptr<core::scene::scene_producer> root(spl::make_shared<core::scene::scene_producer>(doc.width(), doc.height(), format_desc));
+ spl::shared_ptr<core::scene::scene_producer> root(spl::make_shared<core::scene::scene_producer>(doc.width(), doc.height(), dependencies.format_desc));
layer_link_constructor link_constructor;
core::text::text_info text_info(std::move(get_text_info((*it)->text_data())));
text_info.size *= (*it)->text_scale();
- auto text_producer = core::text_producer::create(frame_factory, 0, 0, str, text_info, doc.width(), doc.height());
+ auto text_producer = core::text_producer::create(dependencies.frame_factory, 0, 0, str, text_info, doc.width(), doc.height());
core::text::string_metrics metrics = text_producer->measure_string(str);
new_layer.hidden.set(!(*it)->is_visible());
if ((*it)->has_timeline())
- create_timelines(root, format_desc, new_layer, (*it), adjustment_x, adjustment_y);
+ create_timelines(root, dependencies.format_desc, new_layer, (*it), adjustment_x, adjustment_y);
if((*it)->link_group_id() != 0)
link_constructor.add(&new_layer, (*it)->link_group_id(), (*it)->is_position_protected(), -adjustment_x, -adjustment_y);
std::shared_ptr<core::frame_producer> layer_producer;
if((*it)->is_solid())
{
- layer_producer = core::create_const_producer(core::create_color_frame(it->get(), frame_factory, (*it)->solid_color().to_uint32()), (*it)->bitmap()->width(), (*it)->bitmap()->height());
+ layer_producer = core::create_const_producer(core::create_color_frame(it->get(), dependencies.frame_factory, (*it)->solid_color().to_uint32()), (*it)->bitmap()->width(), (*it)->bitmap()->height());
}
else if((*it)->bitmap())
{
core::pixel_format_desc pfd(core::pixel_format::bgra);
pfd.planes.push_back(core::pixel_format_desc::plane((*it)->bitmap()->width(), (*it)->bitmap()->height(), 4));
- auto frame = frame_factory->create_frame(it->get(), pfd);
+ auto frame = dependencies.frame_factory->create_frame(it->get(), pfd);
memcpy(frame.image_data().data(), (*it)->bitmap()->data(), frame.image_data().size());
layer_producer = core::create_const_producer(core::draw_frame(std::move(frame)), (*it)->bitmap()->width(), (*it)->bitmap()->height());
new_layer.hidden.set(!(*it)->is_visible());
if ((*it)->has_timeline())
- create_timelines(root, format_desc, new_layer, (*it), 0, 0);
+ create_timelines(root, dependencies.format_desc, new_layer, (*it), 0, 0);
if((*it)->link_group_id() != 0)
link_constructor.add(&new_layer, (*it)->link_group_id(), (*it)->is_position_protected(), 0, 0);
text_layer.second->text().bind(root->create_variable<std::wstring>(boost::to_lower_copy(text_layer.first), true, L""));
if (doc.has_timeline())
- create_marks(root, format_desc, doc.timeline());
+ create_marks(root, dependencies.format_desc, doc.timeline());
auto params2 = params;
params2.erase(params2.begin());
return spl::make_shared<core::scene::scene_cg_proxy>(producer);
},
[](
- const spl::shared_ptr<core::frame_factory>& factory,
- const core::video_format_desc& format_desc,
+ const core::frame_producer_dependencies& dependencies,
const std::wstring& filename)
{
- return create_psd_scene_producer(factory, format_desc, { filename });
+ return create_psd_scene_producer(dependencies, { filename });
},
false);
}
project (reroute)
set(SOURCES
+ producer/channel_producer.cpp
+ producer/layer_producer.cpp
producer/reroute_producer.cpp
+ reroute.cpp
stdafx.cpp
)
set(HEADERS
+ producer/channel_producer.h
+ producer/layer_producer.h
producer/reroute_producer.h
+ reroute.h
stdafx.h
)
include_directories(${BOOST_INCLUDE_PATH})
include_directories(${RXCPP_INCLUDE_PATH})
include_directories(${TBB_INCLUDE_PATH})
+include_directories(${ASMLIB_INCLUDE_PATH})
set_target_properties(reroute PROPERTIES FOLDER modules)
source_group(sources\\producer producer/*)
source_group(sources ./*)
target_link_libraries(reroute common core)
+
+casparcg_add_include_statement("modules/reroute/reroute.h")
+casparcg_add_init_statement("reroute::init" "reroute")
+casparcg_add_module_project("reroute")
--- /dev/null
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "channel_producer.h"
+
+#include <core/monitor/monitor.h>
+#include <core/consumer/frame_consumer.h>
+#include <core/consumer/output.h>
+#include <core/producer/frame_producer.h>
+#include <core/video_channel.h>
+
+#include <core/frame/frame.h>
+#include <core/frame/pixel_format.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/video_format.h>
+
+#include <boost/thread/once.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/range/algorithm/copy.hpp>
+
+#include <common/except.h>
+#include <common/memory.h>
+#include <common/future.h>
+
+#include <tbb/concurrent_queue.h>
+
+#include <asmlib.h>
+
+#include <queue>
+
+namespace caspar { namespace reroute {
+
+class channel_consumer : public core::frame_consumer
+{
+ core::monitor::subject monitor_subject_;
+ tbb::concurrent_bounded_queue<core::const_frame> frame_buffer_;
+ core::video_format_desc format_desc_;
+ int channel_index_;
+ int consumer_index_;
+ tbb::atomic<bool> is_running_;
+ tbb::atomic<int64_t> current_age_;
+ std::promise<void> first_frame_promise_;
+ std::future<void> first_frame_available_;
+ bool first_frame_reported_;
+
+public:
+ channel_consumer()
+ : consumer_index_(next_consumer_index())
+ , first_frame_available_(first_frame_promise_.get_future())
+ , first_frame_reported_(false)
+ {
+ is_running_ = true;
+ current_age_ = 0;
+ frame_buffer_.set_capacity(3);
+ }
+
+ static int next_consumer_index()
+ {
+ static tbb::atomic<int> consumer_index_counter;
+ static boost::once_flag consumer_index_counter_initialized;
+
+ boost::call_once(consumer_index_counter_initialized, [&]()
+ {
+ consumer_index_counter = 0;
+ });
+
+ return ++consumer_index_counter;
+ }
+
+ ~channel_consumer()
+ {
+ }
+
+ // frame_consumer
+
+ std::future<bool> send(core::const_frame frame) override
+ {
+ bool pushed = frame_buffer_.try_push(frame);
+
+ if (pushed && !first_frame_reported_)
+ {
+ first_frame_promise_.set_value();
+ first_frame_reported_ = true;
+ }
+
+ return make_ready_future(is_running_.load());
+ }
+
+ void initialize(
+ const core::video_format_desc& format_desc,
+ int channel_index) override
+ {
+ format_desc_ = format_desc;
+ channel_index_ = channel_index;
+ }
+
+ std::wstring name() const override
+ {
+ return L"channel-consumer";
+ }
+
+ std::wstring print() const override
+ {
+ return L"[channel-consumer|" + boost::lexical_cast<std::wstring>(channel_index_) + L"]";
+ }
+
+ boost::property_tree::wptree info() const override
+ {
+ boost::property_tree::wptree info;
+ info.add(L"type", L"channel-consumer");
+ info.add(L"channel-index", channel_index_);
+ return info;
+ }
+
+ bool has_synchronization_clock() const override
+ {
+ return false;
+ }
+
+ int buffer_depth() const override
+ {
+ return -1;
+ }
+
+ int index() const override
+ {
+ return 78500 + consumer_index_;
+ }
+
+ core::monitor::subject& monitor_output() override
+ {
+ return monitor_subject_;
+ }
+
+ // channel_consumer
+
+ const core::video_format_desc& get_video_format_desc()
+ {
+ return format_desc_;
+ }
+
+ void block_until_first_frame_available()
+ {
+ if (first_frame_available_.wait_for(std::chrono::seconds(2)) == std::future_status::timeout)
+ CASPAR_LOG(warning)
+ << print() << L" Timed out while waiting for first frame";
+ }
+
+ core::const_frame receive()
+ {
+ core::const_frame frame = core::const_frame::empty();
+
+ if (!is_running_)
+ return frame;
+
+ frame_buffer_.try_pop(frame);
+ //if (frame_buffer_.try_pop(frame))
+// current_age_ = frame.get_age_millis();
+
+ return frame;
+ }
+
+ void stop()
+ {
+ is_running_ = false;
+ }
+};
+
+class channel_producer : public core::frame_producer_base
+{
+ core::monitor::subject monitor_subject_;
+
+ const spl::shared_ptr<core::frame_factory> frame_factory_;
+ const core::video_format_desc output_format_desc_;
+ const spl::shared_ptr<channel_consumer> consumer_;
+ core::constraints pixel_constraints_;
+
+ std::queue<core::draw_frame> frame_buffer_;
+ uint64_t frame_number_;
+
+public:
+ explicit channel_producer(const core::frame_producer_dependencies& dependecies, const spl::shared_ptr<core::video_channel>& channel)
+ : frame_factory_(dependecies.frame_factory)
+ , output_format_desc_(dependecies.format_desc)
+ , frame_number_(0)
+ {
+ pixel_constraints_.width.set(output_format_desc_.width);
+ pixel_constraints_.height.set(output_format_desc_.height);
+ channel->output().add(consumer_);
+ consumer_->block_until_first_frame_available();
+ CASPAR_LOG(info) << print() << L" Initialized";
+ }
+
+ ~channel_producer()
+ {
+ consumer_->stop();
+ CASPAR_LOG(info) << print() << L" Uninitialized";
+ }
+
+ // frame_producer
+
+ core::draw_frame receive_impl() override
+ {
+ auto format_desc = consumer_->get_video_format_desc();
+
+ if(frame_buffer_.size() > 0)
+ {
+ auto frame = frame_buffer_.front();
+ frame_buffer_.pop();
+ return frame;
+ }
+
+ auto read_frame = consumer_->receive();
+ if(read_frame == core::const_frame::empty() || read_frame.image_data().empty())
+ return core::draw_frame::late();
+
+ frame_number_++;
+
+ bool double_speed = std::abs(output_format_desc_.fps / 2.0 - format_desc.fps) < 0.01;
+ bool half_speed = std::abs(format_desc.fps / 2.0 - output_format_desc_.fps) < 0.01;
+
+ if(half_speed && frame_number_ % 2 == 0) // Skip frame
+ return receive_impl();
+
+ core::pixel_format_desc desc;
+ desc.format = core::pixel_format::bgra;
+ desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));
+ auto frame = frame_factory_->create_frame(this, desc);
+
+ bool copy_audio = !double_speed && !half_speed;
+
+ if (copy_audio)
+ {
+ frame.audio_data().reserve(read_frame.audio_data().size());
+ boost::copy(read_frame.audio_data(), std::back_inserter(frame.audio_data()));
+ }
+
+ A_memcpy(frame.image_data().begin(), read_frame.image_data().begin(), read_frame.image_data().size());
+
+ frame_buffer_.push(core::draw_frame(std::move(frame)));
+
+ if(double_speed)
+ frame_buffer_.push(frame_buffer_.back());
+
+ return receive_impl();
+ }
+
+ std::wstring name() const override
+ {
+ return L"channel-producer";
+ }
+
+ std::wstring print() const override
+ {
+ return L"channel-producer[]";
+ }
+
+ core::constraints& pixel_constraints() override
+ {
+ return pixel_constraints_;
+ }
+
+ boost::property_tree::wptree info() const override
+ {
+ boost::property_tree::wptree info;
+ info.add(L"type", L"channel-producer");
+ return info;
+ }
+
+ core::monitor::subject& monitor_output() override
+ {
+ return monitor_subject_;
+ }
+};
+
+spl::shared_ptr<core::frame_producer> create_channel_producer(
+ const core::frame_producer_dependencies& dependencies,
+ const spl::shared_ptr<core::video_channel>& channel)
+{
+ return spl::make_shared<channel_producer>(dependencies, channel);
+}
+
+}}
\ No newline at end of file
--- /dev/null
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/fwd.h>
+
+namespace caspar { namespace reroute {
+
+spl::shared_ptr<core::frame_producer> create_channel_producer(
+ const core::frame_producer_dependencies& dependencies,
+ const spl::shared_ptr<core::video_channel>& channel);
+
+}}
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "layer_producer.h"
+
+#include <core/consumer/write_frame_consumer.h>
+#include <core/consumer/output.h>
+#include <core/video_channel.h>
+#include <core/frame/draw_frame.h>
+#include <core/frame/frame_factory.h>
+#include <core/producer/frame_producer.h>
+#include <core/producer/stage.h>
+
+#include <common/except.h>
+#include <common/future.h>
+
+#include <boost/format.hpp>
+
+#include <tbb/concurrent_queue.h>
+
+namespace caspar { namespace reroute {
+
+class layer_consumer : public core::write_frame_consumer
+{
+ tbb::concurrent_bounded_queue<core::draw_frame> frame_buffer_;
+ std::promise<void> first_frame_promise_;
+ std::future<void> first_frame_available_;
+ bool first_frame_reported_;
+
+public:
+ layer_consumer()
+ : first_frame_available_(first_frame_promise_.get_future())
+ , first_frame_reported_(false)
+ {
+ frame_buffer_.set_capacity(2);
+ }
+
+ ~layer_consumer()
+ {
+ }
+
+ // write_frame_consumer
+
+ void send(const core::draw_frame& src_frame) override
+ {
+ bool pushed = frame_buffer_.try_push(src_frame);
+
+ if (pushed && !first_frame_reported_)
+ {
+ first_frame_promise_.set_value();
+ first_frame_reported_ = true;
+ }
+ }
+
+ std::wstring print() const override
+ {
+ return L"[layer_consumer]";
+ }
+
+ core::draw_frame receive()
+ {
+ core::draw_frame frame;
+ if (!frame_buffer_.try_pop(frame))
+ {
+ return core::draw_frame::late();
+ }
+ return frame;
+ }
+
+ void block_until_first_frame_available()
+ {
+ if (first_frame_available_.wait_for(std::chrono::seconds(2)) == std::future_status::timeout)
+ CASPAR_LOG(warning)
+ << print() << L" Timed out while waiting for first frame";
+ }
+};
+
+class layer_producer : public core::frame_producer_base
+{
+ core::monitor::subject monitor_subject_;
+
+ const int layer_;
+ const spl::shared_ptr<layer_consumer> consumer_;
+
+ core::draw_frame last_frame_;
+ uint64_t frame_number_;
+
+ const spl::shared_ptr<core::video_channel> channel_;
+ core::constraints pixel_constraints_;
+
+public:
+ explicit layer_producer(const spl::shared_ptr<core::video_channel>& channel, int layer)
+ : layer_(layer)
+ , channel_(channel)
+ , last_frame_(core::draw_frame::empty())
+ , frame_number_(0)
+ {
+ pixel_constraints_.width.set(channel->video_format_desc().width);
+ pixel_constraints_.height.set(channel->video_format_desc().height);
+ channel_->stage().add_layer_consumer(this, layer_, consumer_);
+ consumer_->block_until_first_frame_available();
+ CASPAR_LOG(info) << print() << L" Initialized";
+ }
+
+ ~layer_producer()
+ {
+ channel_->stage().remove_layer_consumer(this, layer_);
+ CASPAR_LOG(info) << print() << L" Uninitialized";
+ }
+
+ // frame_producer
+
+ core::draw_frame receive_impl() override
+ {
+ auto consumer_frame = consumer_->receive();
+ if (consumer_frame == core::draw_frame::late())
+ return last_frame_;
+
+ frame_number_++;
+ return last_frame_ = consumer_frame;
+ }
+
+ std::wstring print() const override
+ {
+ return L"layer-producer[" + boost::lexical_cast<std::wstring>(layer_) + L"]";
+ }
+
+ std::wstring name() const override
+ {
+ return L"layer-producer";
+ }
+
+ boost::property_tree::wptree info() const override
+ {
+ boost::property_tree::wptree info;
+ info.add(L"type", L"layer-producer");
+ return info;
+ }
+
+ core::monitor::subject& monitor_output() override
+ {
+ return monitor_subject_;
+ }
+
+ core::constraints& pixel_constraints() override
+ {
+ return pixel_constraints_;
+ }
+};
+
+spl::shared_ptr<core::frame_producer> create_layer_producer(const spl::shared_ptr<core::video_channel>& channel, int layer)
+{
+ return spl::make_shared<layer_producer>(channel, layer);
+}
+
+}}
\ No newline at end of file
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Cambell Prince, cambell.prince@gmail.com
+*/
+
+#pragma once
+
+#include <common/memory.h>
+
+#include <core/fwd.h>
+
+namespace caspar { namespace reroute {
+
+spl::shared_ptr<core::frame_producer> create_layer_producer(const spl::shared_ptr<core::video_channel>& channel, int layer);
+
+}}
#include "../stdafx.h"
#include "reroute_producer.h"
+#include "layer_producer.h"
+#include "channel_producer.h"
#include <core/producer/frame_producer.h>
-#include <core/frame/draw_frame.h>
-#include <core/frame/frame_factory.h>
-#include <core/frame/pixel_format.h>
-#include <core/frame/frame.h>
#include <core/video_channel.h>
-#include <core/producer/stage.h>
-#include <common/except.h>
-#include <common/diagnostics/graph.h>
-#include <common/log.h>
-#include <common/reactive.h>
-#include <common/linq.h>
-
-#include <tbb/concurrent_queue.h>
-
-#include <boost/property_tree/ptree.hpp>
-#include <boost/optional.hpp>
-
-#include <queue>
+#include <boost/algorithm/string.hpp>
+#include <boost/range/algorithm/find_if.hpp>
namespace caspar { namespace reroute {
-class reroute_producer : public reactive::observer<std::map<int, core::draw_frame>>
- , public core::frame_producer_base
+spl::shared_ptr<core::frame_producer> create_producer(
+ const core::frame_producer_dependencies& dependencies,
+ const std::vector<std::wstring>& params)
{
- core::monitor::subject monitor_subject_;
+ static const std::wstring PREFIX = L"route://";
- core::constraints constraints_;
- const spl::shared_ptr<diagnostics::graph> graph_;
-
- tbb::concurrent_bounded_queue<std::map<int, core::draw_frame>> input_buffer_;
-public:
- explicit reroute_producer()
+ if (params.empty() ||
+ !boost::starts_with(params.at(0), PREFIX) ||
+ boost::ends_with(params.at(0), L"_A") ||
+ boost::ends_with(params.at(0), L"_ALPHA"))
{
- graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));
- graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));
- graph_->set_text(print());
- diagnostics::register_graph(graph_);
-
- input_buffer_.set_capacity(1);
+ return core::frame_producer::empty();
}
-
- // observable
- void on_next(const std::map<int, core::draw_frame>& frames)
- {
- if(!input_buffer_.try_push(frames))
- graph_->set_tag("dropped-frame");
- }
+ auto& url = params.at(0);
+ auto channel_layer_spec = url.substr(PREFIX.length());
+ auto dash = channel_layer_spec.find(L"-");
+ bool has_layer_spec = dash != std::wstring::npos;
+ int channel_id;
- // frame_producer
-
- core::draw_frame receive_impl() override
- {
- std::map<int, core::draw_frame> frames;
- if(!input_buffer_.try_pop(frames))
- {
- graph_->set_tag("late-frame");
- return core::draw_frame::late();
- }
+ if (has_layer_spec)
+ channel_id = boost::lexical_cast<int>(channel_layer_spec.substr(0, dash));
+ else
+ channel_id = boost::lexical_cast<int>(channel_layer_spec);
- return cpplinq::from(frames)
- .select(values())
- .aggregate(core::draw_frame::empty(), core::draw_frame::over);
- }
+ auto found_channel = boost::find_if(dependencies.channels, [=](spl::shared_ptr<core::video_channel> ch) { return ch->index() == channel_id; });
- core::constraints& pixel_constraints() override
- {
- return constraints_;
- }
-
- std::wstring print() const override
- {
- return L"reroute[]";
- }
+ if (found_channel == dependencies.channels.end())
+ CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(L"No channel with id " + channel_id));
- std::wstring name() const override
+ if (has_layer_spec)
{
- return L"reroute";
- }
+ auto layer = boost::lexical_cast<int>(channel_layer_spec.substr(dash + 1));
- boost::property_tree::wptree info() const override
- {
- boost::property_tree::wptree info;
- info.add(L"type", L"rerotue-producer");
- return info;
+ return create_layer_producer(*found_channel, layer);
}
-
- core::monitor::subject& monitor_output()
+ else
{
- return monitor_subject_;
+ return create_channel_producer(dependencies, *found_channel);
}
-};
-
-spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel)
-{
- auto producer = spl::make_shared<reroute_producer>();
-
- std::weak_ptr<reactive::observer<std::map<int, core::draw_frame>>> o = producer;
-
- //channel.stage().monitor_output().link_target.subscribe(o);
-
- return producer;
}
}}
\ No newline at end of file
#include <core/fwd.h>
+#include <vector>
+#include <string>
+
namespace caspar { namespace reroute {
-spl::shared_ptr<core::frame_producer> create_producer(core::video_channel& channel);
+spl::shared_ptr<core::frame_producer> create_producer(
+ const core::frame_producer_dependencies& dependencies,
+ const std::vector<std::wstring>& params);
}}
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#include "stdafx.h"
+
+#include "reroute.h"
+
+#include "producer/reroute_producer.h"
+#include <core/producer/frame_producer.h>
+
+namespace caspar { namespace reroute {
+
+void init(core::module_dependencies dependencies)
+{
+ core::register_producer_factory(reroute::create_producer);
+}
+
+}}
--- /dev/null
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <core/module_dependencies.h>
+
+namespace caspar { namespace reroute {
+
+void init(core::module_dependencies dependencies);
+
+}}
#include "../util/ClientInfo.h"
#include "amcp_shared.h"
#include <core/consumer/frame_consumer.h>
+#include <core/producer/frame_producer.h>
#include <boost/algorithm/string.hpp>
AMCPChannelsAwareCommand(const AMCPChannelsAwareCommand& rhs) : channels_(rhs.channels_) {}
const std::vector<channel_context>& channels() { return channels_; }
+ core::frame_producer_dependencies get_dependencies(const spl::shared_ptr<core::video_channel>& channel)
+ {
+ return core::frame_producer_dependencies(
+ channel->frame_factory(),
+ cpplinq::from(channels())
+ .select([](channel_context c) { return c.channel; })
+ .to_vector(),
+ channel->video_format_desc());
+ }
private:
const std::vector<channel_context>& channels_;
#include <core/diagnostics/osd_graph.h>
#include <core/system_info_provider.h>
-#include <modules/reroute/producer/reroute_producer.h>
-
#include <algorithm>
#include <locale>
#include <fstream>
if(channel.channel != self)
{
core::diagnostics::call_context::for_thread().layer = index;
- auto producer = reroute::create_producer(*channel.channel);
+ auto producer = create_producer(get_dependencies(channel.channel), L"route://" + boost::lexical_cast<std::wstring>(channel.channel->index()));
self->stage().load(index, producer, false);
self->stage().play(index);
index++;
}
}
- int n = channels().size()-1;
- double delta = 1.0/static_cast<double>(n);
- for(int x = 0; x < n; ++x)
- {
- for(int y = 0; y < n; ++y)
- {
- int index = x+y*n+1;
- auto transform = [=](frame_transform transform) -> frame_transform
- {
- transform.image_transform.fill_translation[0] = x*delta;
- transform.image_transform.fill_translation[1] = y*delta;
- transform.image_transform.fill_scale[0] = delta;
- transform.image_transform.fill_scale[1] = delta;
- transform.image_transform.clip_translation[0] = x*delta;
- transform.image_transform.clip_translation[1] = y*delta;
- transform.image_transform.clip_scale[0] = delta;
- transform.image_transform.clip_scale[1] = delta;
- return transform;
- };
- self->stage().apply_transform(index, transform);
- }
- }
+ MixerCommand mixer(client(), channels().back(), self->index(), -1);
+ auto num_channels = channels().size() - 1;
+ int square_side_length = std::ceil(std::sqrt(num_channels));
+ mixer.parameters().push_back(L"GRID");
+ mixer.parameters().push_back(boost::lexical_cast<std::wstring>(square_side_length));
+ mixer.Execute();
return true;
}
core::diagnostics::scoped_call_context save;
core::diagnostics::call_context::for_thread().video_channel = channel_index() + 1;
core::diagnostics::call_context::for_thread().layer = layer_index();
- auto pFP = create_producer(channel()->frame_factory(), channel()->video_format_desc(), parameters());
+ auto pFP = create_producer(get_dependencies(channel()), parameters());
channel()->stage().load(layer_index(), pFP, true);
SetReplyString(L"202 LOAD OK\r\n");
//Perform loading of the clip
try
{
- std::shared_ptr<core::frame_producer> pFP;
-
- static boost::wregex expr(LR"(\[(?<CHANNEL>\d+)\])", boost::regex::icase);
-
core::diagnostics::scoped_call_context save;
core::diagnostics::call_context::for_thread().video_channel = channel_index() + 1;
core::diagnostics::call_context::for_thread().layer = layer_index();
- boost::wsmatch what;
- if(boost::regex_match(parameters().at(0), what, expr))
- {
- auto channel_index = boost::lexical_cast<int>(what["CHANNEL"].str());
- pFP = reroute::create_producer(*channels().at(channel_index-1).channel);
- }
- else
- {
- pFP = create_producer(channel()->frame_factory(), channel()->video_format_desc(), parameters());
- }
+ auto pFP = create_producer(get_dependencies(channel()), parameters());
if(pFP == frame_producer::empty())
CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(parameters().size() > 0 ? parameters()[0] : L""));
bool auto_play = contains_param(L"AUTO", parameters());
- auto pFP2 = create_transition_producer(channel()->video_format_desc().field_mode, spl::make_shared_ptr(pFP), transitionInfo);
+ auto pFP2 = create_transition_producer(channel()->video_format_desc().field_mode, pFP, transitionInfo);
if(auto_play)
channel()->stage().load(layer_index(), pFP2, false, transitionInfo.duration); // TODO: LOOP
else
}
auto filename = parameters()[2];
- auto proxy = cg_registry_->get_or_create_proxy(channel(), layer_index(core::cg_proxy::DEFAULT_LAYER), filename);
+ auto proxy = cg_registry_->get_or_create_proxy(channel(), get_dependencies(channel()), layer_index(core::cg_proxy::DEFAULT_LAYER), filename);
if (proxy == core::cg_proxy::empty())
{
bool DoExecute();
};
-class LoadCommand : public AMCPChannelCommandBase<1>
+class LoadCommand : public AMCPChannelCommandBase<1>, AMCPChannelsAwareCommand
{
public:
- LoadCommand(IO::ClientInfoPtr client, const channel_context& channel, unsigned int channel_index, int layer_index) : AMCPChannelCommandBase(client, channel, channel_index, layer_index)
+ LoadCommand(IO::ClientInfoPtr client, const channel_context& channel, unsigned int channel_index, int layer_index, const std::vector<channel_context>& channels) : AMCPChannelCommandBase(client, channel, channel_index, layer_index), AMCPChannelsAwareCommand(channels)
{}
private:
bool DoExecute();
};
-class CGCommand : public AMCPChannelCommandBase<1>
+class CGCommand : public AMCPChannelCommandBase<1>, public AMCPChannelsAwareCommand
{
public:
CGCommand(
const channel_context& channel,
unsigned int channel_index,
int layer_index,
- const spl::shared_ptr<core::cg_producer_registry>& cg_registry)
+ const spl::shared_ptr<core::cg_producer_registry>& cg_registry,
+ const std::vector<channel_context>& channels)
: AMCPChannelCommandBase(client, channel, channel_index, layer_index)
+ , AMCPChannelsAwareCommand(channels)
, cg_registry_(cg_registry)
{
}
if ( s == L"MIXER") return std::make_shared<MixerCommand>(client, channel, channel_index, layer_index);
else if (s == L"CALL") return std::make_shared<CallCommand>(client, channel, channel_index, layer_index);
else if (s == L"SWAP") return std::make_shared<SwapCommand>(client, channel, channel_index, layer_index, channels_);
- else if (s == L"LOAD") return std::make_shared<LoadCommand>(client, channel, channel_index, layer_index);
+ else if (s == L"LOAD") return std::make_shared<LoadCommand>(client, channel, channel_index, layer_index, channels_);
else if (s == L"LOADBG") return std::make_shared<LoadbgCommand>(client, channel, channel_index, layer_index, channels_);
else if (s == L"ADD") return std::make_shared<AddCommand>(client, channel, channel_index, layer_index);
else if (s == L"REMOVE") return std::make_shared<RemoveCommand>(client, channel, channel_index, layer_index);
else if (s == L"STOP") return std::make_shared<StopCommand>(client, channel, channel_index, layer_index);
else if (s == L"CLEAR") return std::make_shared<ClearCommand>(client, channel, channel_index, layer_index);
else if (s == L"PRINT") return std::make_shared<PrintCommand>(client, channel, channel_index, layer_index);
- else if (s == L"CG") return std::make_shared<CGCommand>(client, channel, channel_index, layer_index, cg_registry_);
+ else if (s == L"CG") return std::make_shared<CGCommand>(client, channel, channel_index, layer_index, cg_registry_, channels_);
else if (s == L"SET") return std::make_shared<SetCommand>(client, channel, channel_index, layer_index);
return nullptr;
auto xmlData2 = boost::locale::conv::utf_to_utf<wchar_t, char>(std::string(xmlData_.begin(), xmlData_.end()));
auto proxy = pCIIStrategy_->get_cg_registry()->get_or_create_proxy(
pCIIStrategy_->GetChannel(),
+ pCIIStrategy_->get_dependencies(),
core::cg_proxy::DEFAULT_LAYER,
filename_);
proxy->add(layer_, filename_, false, L"", xmlData2);
const spl::shared_ptr<core::cg_producer_registry>& cg_registry)
: executor_(L"CIIProtocolStrategy")
, pChannel_(channels.at(0))
+ , channels_(channels)
, cg_registry_(cg_registry)
{
}
core::diagnostics::scoped_call_context save;
core::diagnostics::call_context::for_thread().video_channel = 1;
core::diagnostics::call_context::for_thread().layer = 0;
- auto producer = cg_registry_->create_producer(GetChannel(), fullTemplateFilename);
+ auto producer = cg_registry_->create_producer(get_dependencies(), fullTemplateFilename);
if (producer == core::frame_producer::empty())
{
core::diagnostics::call_context::for_thread().video_channel = 1;
core::diagnostics::call_context::for_thread().layer = 0;
- auto pFP = create_producer(GetChannel()->frame_factory(), GetChannel()->video_format_desc(), filename);
+ auto pFP = create_producer(get_dependencies(), filename);
auto pTransition = create_transition_producer(GetChannel()->video_format_desc().field_mode, pFP, transition);
try
spl::shared_ptr<core::video_channel> GetChannel() const { return pChannel_; }
spl::shared_ptr<core::cg_producer_registry> get_cg_registry() const { return cg_registry_; }
+ core::frame_producer_dependencies get_dependencies() const { return core::frame_producer_dependencies(GetChannel()->frame_factory(), channels_, GetChannel()->video_format_desc()); }
void DisplayMediaFile(const std::wstring& filename);
void DisplayTemplate(const std::wstring& titleName);
std::wstring currentProfile_;
spl::shared_ptr<core::video_channel> pChannel_;
spl::shared_ptr<core::cg_producer_registry> cg_registry_;
+ std::vector<spl::shared_ptr<core::video_channel>> channels_;
};
}}}
const std::vector<spl::shared_ptr<core::video_channel>>& channels,
const spl::shared_ptr<core::cg_producer_registry>& cg_registry)
{
- add_command_handlers(command_processor_, channels.at(0), cg_registry);
+ add_command_handlers(command_processor_, channels, channels.at(0), cg_registry);
}
IO::protocol_strategy<wchar_t>::ptr clk_protocol_strategy_factory::create(
\r
class command_context\r
{\r
- bool clock_loaded_ = false;\r
- spl::shared_ptr<core::video_channel> channel_;\r
- spl::shared_ptr<core::cg_producer_registry> cg_registry_;\r
+ bool clock_loaded_ = false;\r
+ std::vector<spl::shared_ptr<core::video_channel>> channels_;\r
+ spl::shared_ptr<core::video_channel> channel_;\r
+ spl::shared_ptr<core::cg_producer_registry> cg_registry_;\r
public:\r
command_context(\r
+ const std::vector<spl::shared_ptr<core::video_channel>>& channels,\r
const spl::shared_ptr<core::video_channel>& channel,\r
const spl::shared_ptr<core::cg_producer_registry>& cg_registry)\r
- : channel_(channel)\r
+ : channels_(channels)\r
+ , channel_(channel)\r
, cg_registry_(cg_registry)\r
{\r
}\r
{\r
if (!clock_loaded_) \r
{\r
- cg_registry_->get_or_create_proxy(channel_, core::cg_proxy::DEFAULT_LAYER, L"hawrysklocka/clock")->add(\r
+ core::frame_producer_dependencies dependencies(channel_->frame_factory(), channels_, channel_->video_format_desc());\r
+ cg_registry_->get_or_create_proxy(channel_, dependencies, core::cg_proxy::DEFAULT_LAYER, L"hawrysklocka/clock")->add(\r
0, L"hawrysklocka/clock", true, L"", data);\r
clock_loaded_ = true;\r
}\r
}\r
\r
void add_command_handlers(\r
- clk_command_processor& processor, \r
+ clk_command_processor& processor,\r
+ const std::vector<spl::shared_ptr<core::video_channel>>& channels,\r
const spl::shared_ptr<core::video_channel>& channel,\r
const spl::shared_ptr<core::cg_producer_registry>& cg_registry)\r
{\r
- auto context = spl::make_shared<command_context>(channel, cg_registry);\r
+ auto context = spl::make_shared<command_context>(channels, channel, cg_registry);\r
\r
processor\r
.add_handler(L"DUR", \r
* @param channel The channel to play the flash graphics on.\r
*/\r
void add_command_handlers(\r
- clk_command_processor& processor, \r
+ clk_command_processor& processor,\r
+ const std::vector<spl::shared_ptr<core::video_channel>>& channels,\r
const spl::shared_ptr<core::video_channel>& channel,\r
const spl::shared_ptr<core::cg_producer_registry>& cg_registry);\r
\r