#include <boost/thread.hpp>
#include <future>
+#include <vector>
+#include <map>
namespace caspar { namespace core {
std::vector<consumer_factory_t> g_factories;
+std::map<std::wstring, preconfigured_consumer_factory_t> g_preconfigured_factories;
void register_consumer_factory(const consumer_factory_t& factory)
{
g_factories.push_back(factory);
}
+void register_preconfigured_consumer_factory(
+ const std::wstring& element_name,
+ const preconfigured_consumer_factory_t& factory)
+{
+ g_preconfigured_factories.insert(std::make_pair(element_name, factory));
+}
+
class destroy_consumer_proxy : public frame_consumer
{
std::shared_ptr<frame_consumer> consumer_;
monitor::subject& monitor_output() override {return consumer_->monitor_output();}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, interaction_sink* sink)
{
if(params.empty())
CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));
{
try
{
- consumer = factory(params);
+ consumer = factory(params, sink);
}
catch(...)
{
std::move(consumer)))));
}
+spl::shared_ptr<frame_consumer> create_consumer(
+ const std::wstring& element_name,
+ const boost::property_tree::wptree& element,
+ interaction_sink* sink)
+{
+ auto found = g_preconfigured_factories.find(element_name);
+
+ if (found == g_preconfigured_factories.end())
+ CASPAR_THROW_EXCEPTION(file_not_found()
+ << msg_info(L"No consumer factory registered for element name " + element_name));
+
+ return spl::make_shared<destroy_consumer_proxy>(
+ spl::make_shared<print_consumer_proxy>(
+ spl::make_shared<recover_consumer_proxy>(
+ spl::make_shared<cadence_guard>(
+ found->second(element, sink)))));
+}
+
const spl::shared_ptr<frame_consumer>& frame_consumer::empty()
{
class empty_frame_consumer : public frame_consumer
namespace caspar { namespace core {
+struct interaction_sink;
+
// Interface
class frame_consumer
{
virtual int index() const = 0;
};
-typedef std::function<spl::shared_ptr<frame_consumer>(const std::vector<std::wstring>&)> consumer_factory_t;
+typedef std::function<spl::shared_ptr<frame_consumer>(
+ const std::vector<std::wstring>&,
+ interaction_sink* sink)> consumer_factory_t;
+typedef std::function<spl::shared_ptr<frame_consumer>(
+ const boost::property_tree::wptree& element,
+ interaction_sink* sink)> preconfigured_consumer_factory_t;
void register_consumer_factory(const consumer_factory_t& factory);
-spl::shared_ptr<frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-
-}}
\ No newline at end of file
+void register_preconfigured_consumer_factory(
+ const std::wstring& element_name,
+ const preconfigured_consumer_factory_t& factory);
+spl::shared_ptr<frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params,
+ interaction_sink* sink);
+spl::shared_ptr<frame_consumer> create_consumer(
+ const std::wstring& element_name,
+ const boost::property_tree::wptree& element,
+ interaction_sink* sink);
+
+}}
}
catch(...){}
- core::register_consumer_factory([](const std::vector<std::wstring>& params)
- {
- return create_consumer(params);
- });
+ core::register_consumer_factory(create_consumer);
+ core::register_preconfigured_consumer_factory(L"bluefish", create_preconfigured_consumer);
repo->register_system_info_provider([](boost::property_tree::wptree& info)
{
info.add(L"system.bluefish.version", version());
}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, core::interaction_sink*)
{
if(params.size() < 1 || params[0] != L"BLUEFISH")
return core::frame_consumer::empty();
return spl::make_shared<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);
}
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree)
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree& ptree, core::interaction_sink*)
{
const auto device_index = ptree.get(L"device", 1);
const auto embedded_audio = ptree.get(L"embedded-audio", false);
namespace core {
class frame_consumer;
+ struct interaction_sink;
}
namespace bluefish {
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree& ptree, core::interaction_sink*);
}}
\ No newline at end of file
}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, core::interaction_sink*)
{
if(params.size() < 1 || params[0] != L"DECKLINK")
return core::frame_consumer::empty();
return spl::make_shared<decklink_consumer_proxy>(config);
}
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree)
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree& ptree, core::interaction_sink*)
{
configuration config;
namespace core {
class frame_consumer;
+ struct interaction_sink;
}
namespace decklink {
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree& ptree, core::interaction_sink*);
}}
\ No newline at end of file
if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))
return;
- core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+ core::register_consumer_factory(create_consumer);
+ core::register_preconfigured_consumer_factory(L"decklink", create_preconfigured_consumer);
core::register_producer_factory(create_producer);
repo->register_system_info_provider([](boost::property_tree::wptree& info)
{
return consumer_->monitor_output();
}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, core::interaction_sink*)
{
auto params2 = params;
auto separate_key_it = std::find(params2.begin(), params2.end(), L"SEPARATE_KEY");
return spl::make_shared<ffmpeg_consumer_proxy>(env::media_folder() + path["PATH"].str(), options, separate_key);
}
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree)
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree& ptree, core::interaction_sink*)
{
auto filename = ptree.get<std::wstring>(L"path");
auto codec = ptree.get(L"vcodec", L"libx264");
namespace core {
class frame_consumer;
+ struct interaction_sink;
}
namespace ffmpeg {
-
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree);
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink*);
}}
\ No newline at end of file
avformat_network_init();
avcodec_register_all();
- core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+ core::register_consumer_factory(create_consumer);
+ core::register_preconfigured_consumer_factory(L"file", create_preconfigured_consumer);
core::register_producer_factory(create_producer);
media_info_repo->register_extractor(
}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
{
if (params.size() < 1 || params[0] != L"IMAGE")
return core::frame_consumer::empty();
namespace image {
- void write_cropped_png(
+void write_cropped_png(
const class core::const_frame& frame,
const core::video_format_desc& format_desc,
const boost::filesystem::wpath& output_file,
int width,
int height);
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, struct core::interaction_sink*);
}}
\ No newline at end of file
core::register_producer_factory(create_scroll_producer);
core::register_producer_factory(create_producer);
core::register_thumbnail_producer_factory(create_thumbnail_producer);
- core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+ core::register_consumer_factory(create_consumer);
repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
{
if (extension == L".TGA"
}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
{
if(params.size() < 1 || params[0] != L"AUDIO")
return core::frame_consumer::empty();
return spl::make_shared<oal_consumer>();
}
-spl::shared_ptr<core::frame_consumer> create_consumer()
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(const boost::property_tree::wptree&, core::interaction_sink*)
{
return spl::make_shared<oal_consumer>();
}
#include <vector>
+#include <boost/property_tree/ptree_fwd.hpp>
+
namespace caspar {
namespace core {
class frame_consumer;
+ struct interaction_sink;
}
namespace oal {
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer();
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params, core::interaction_sink*);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree&, core::interaction_sink*);
}}
\ No newline at end of file
void init()
{
- core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+ core::register_consumer_factory(create_consumer);
+ core::register_preconfigured_consumer_factory(L"system-audio", create_preconfigured_consumer);
}
}}
\ No newline at end of file
#include <core/video_format.h>
#include <core/frame/frame.h>
#include <core/consumer/frame_consumer.h>
+#include <core/interaction/interaction_sink.h>
#include <boost/timer.hpp>
#include <boost/circular_buffer.hpp>
}
};
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)
+spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink* sink)
{
if(params.size() < 1 || params[0] != L"SCREEN")
return core::frame_consumer::empty();
if(params.size() > 1)
config.screen_index = boost::lexical_cast<int>(params[1]);
- config.key_only = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();
- config.key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();
+ config.windowed = std::find(params.begin(), params.end(), L"WINDOWED") != params.end();
+ config.key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();
+ config.interactive = std::find(params.begin(), params.end(), L"INTERACTIVE") != params.end();
auto name_it = std::find(params.begin(), params.end(), L"NAME");
if(name_it != params.end() && ++name_it != params.end())
config.name = *name_it;
- return spl::make_shared<screen_consumer_proxy>(config, nullptr);
+ return spl::make_shared<screen_consumer_proxy>(config, sink);
}
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink* sink)
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink* sink)
{
configuration config;
config.name = ptree.get(L"name", config.name);
#pragma once
#include <common/memory.h>
-#include <core/interaction/interaction_sink.h>
#include <vector>
#include <boost/property_tree/ptree.hpp>
namespace core {
class frame_consumer;
+ struct interaction_sink;
}
namespace screen {
-spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);
-spl::shared_ptr<core::frame_consumer> create_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink* sink);
+spl::shared_ptr<core::frame_consumer> create_consumer(
+ const std::vector<std::wstring>& params,
+ core::interaction_sink* sink);
+spl::shared_ptr<core::frame_consumer> create_preconfigured_consumer(
+ const boost::property_tree::wptree& ptree,
+ core::interaction_sink* sink);
}}
\ No newline at end of file
void init()
{
- caspar::core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_consumer(params);});
+ core::register_consumer_factory(create_consumer);
+ core::register_preconfigured_consumer_factory(L"screen", create_preconfigured_consumer);
}
}}
\ No newline at end of file
params.push_back(L"0");
params.push_back(L"NAME");
params.push_back(L"Channel Grid Window");
- auto screen = create_consumer(params);
+ auto screen = create_consumer(params, &self->stage());
self->output().add(screen);
core::diagnostics::scoped_call_context save;
core::diagnostics::call_context::for_thread().video_channel = channel_index() + 1;
- auto consumer = create_consumer(parameters());
+ auto consumer = create_consumer(parameters(), &channel()->stage());
channel()->output().add(layer_index(consumer->index()), consumer);
SetReplyString(L"202 ADD OK\r\n");
boost::to_upper(str);
}
- index = create_consumer(parameters())->index();
+ index = create_consumer(parameters(), &channel()->stage())->index();
}
channel()->output().remove(index);
bool PrintCommand::DoExecute()
{
- channel()->output().add(create_consumer({ L"IMAGE" }));
+ channel()->output().add(create_consumer({ L"IMAGE" }, &channel()->stage()));
SetReplyString(L"202 PRINT OK\r\n");
#include <modules/image/consumer/image_consumer.h>
#include <modules/psd/psd_scene_producer.h>
-#include <modules/oal/consumer/oal_consumer.h>
-#include <modules/bluefish/consumer/bluefish_consumer.h>
-#include <modules/decklink/consumer/decklink_consumer.h>
-#include <modules/screen/consumer/screen_consumer.h>
-#include <modules/ffmpeg/consumer/ffmpeg_consumer.h>
-
#include <protocol/asio/io_service_manager.h>
#include <protocol/amcp/AMCPProtocolStrategy.h>
#include <protocol/cii/CIIProtocolStrategy.h>
try
{
auto name = xml_consumer.first;
- if(name == L"screen")
- channel->output().add(caspar::screen::create_consumer(xml_consumer.second, &channel->stage()));
- else if(name == L"bluefish")
- channel->output().add(bluefish::create_consumer(xml_consumer.second));
- else if(name == L"decklink")
- channel->output().add(decklink::create_consumer(xml_consumer.second));
- else if(name == L"file")
- channel->output().add(ffmpeg::create_consumer(xml_consumer.second));
- else if(name == L"system-audio")
- channel->output().add(oal::create_consumer());
- else if(name != L"<xmlcomment>")
- CASPAR_LOG(warning) << "Invalid consumer: " << name;
+
+ if (name != L"<xmlcomment>")
+ channel->output().add(create_consumer(name, xml_consumer.second, &channel->stage()));
}
catch(...)
{