]> git.sesse.net Git - casparcg/commitdiff
[CG] Created producer that wraps a CG producer in a way that it can be treated as...
authorHelge Norberg <helge.norberg@svt.se>
Mon, 20 Feb 2017 18:13:31 +0000 (19:13 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Mon, 20 Feb 2017 18:13:31 +0000 (19:13 +0100)
core/producer/cg_proxy.cpp
core/producer/cg_proxy.h
shell/generate_docs.cpp
shell/server.cpp

index 74a1318e83112232f24990856b8773a04755e3cd..94ed28c375321a5ee4114d04a2ff429517e67e64 100644 (file)
 #include "../StdAfx.h"
 
 #include "cg_proxy.h"
+#include "variable.h"
 
 #include "frame_producer.h"
 #include "stage.h"
 #include "../video_channel.h"
 #include "../diagnostics/call_context.h"
+#include "../module_dependencies.h"
+#include "../frame/draw_frame.h"
+#include "../help/help_sink.h"
+#include "../help/help_repository.h"
 
 #include <common/env.h>
 #include <common/os/filesystem.h>
+#include <common/future.h>
 
 #include <boost/thread/mutex.hpp>
 #include <boost/thread/lock_guard.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
 
 #include <future>
 #include <map>
+#include <sstream>
 
 namespace caspar { namespace core {
 
@@ -290,4 +299,184 @@ std::wstring cg_producer_registry::get_cg_producer_name(const std::wstring& file
        return impl_->get_cg_producer_name(filename);
 }
 
+class cg_proxy_as_producer : public frame_producer
+{
+       spl::shared_ptr<frame_producer>                                                 producer_;
+       spl::shared_ptr<cg_proxy>                                                               proxy_;
+       std::wstring                                                                                    template_name_;
+       bool                                                                                                    producer_has_its_own_variables_defined_;
+
+       std::map<std::wstring, std::shared_ptr<core::variable>> variables_;
+       std::vector<std::wstring>                                                               variable_names_;
+       core::binding<std::wstring>                                                             template_data_xml_                                              { [=] { return generate_template_data_xml(); } };
+       std::shared_ptr<void>                                                                   template_data_change_subscription_;
+       bool                                                                                                    is_playing_                                                             = false;
+public:
+       cg_proxy_as_producer(
+                       spl::shared_ptr<frame_producer> producer,
+                       spl::shared_ptr<cg_proxy> proxy,
+                       const std::wstring& template_name,
+                       const std::vector<std::wstring>& parameter_specification)
+               : producer_(std::move(producer))
+               , proxy_(std::move(proxy))
+               , template_name_(std::move(template_name))
+               , producer_has_its_own_variables_defined_(!producer_->get_variables().empty())
+       {
+               if (parameter_specification.size() % 2 != 0)
+                       CASPAR_THROW_EXCEPTION(user_error() << msg_info("Parameter specification must be a sequence of type and parameter name pairs"));
+
+               if (producer_has_its_own_variables_defined_ && !parameter_specification.empty())
+                       CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Producer " + producer_->name() + L" does not need help with available template parameters"));
+
+               for (int i = 0; i < parameter_specification.size(); i += 2)
+               {
+                       auto& type                              = parameter_specification.at(i);
+                       auto& parameter_name    = parameter_specification.at(i + 1);
+
+                       if (type == L"string")
+                               create_parameter<std::wstring>(parameter_name);
+                       else if (type == L"number")
+                               create_parameter<double>(parameter_name);
+                       else
+                               CASPAR_THROW_EXCEPTION(user_error() << msg_info("The type in a parameter specification must be either string or number"));
+               }
+
+               template_data_change_subscription_ = template_data_xml_.on_change([=]
+               {
+                       if (is_playing_)
+                               proxy_->update(0, template_data_xml_.get());
+               });
+       }
+
+       // frame_producer
+
+       std::future<std::wstring> call(const std::vector<std::wstring>& params) override
+       {
+               auto& command = params.at(0);
+
+               if (command == L"play()")
+               {
+                       proxy_->add(0, template_name_, true, L"", template_data_xml_.get());
+                       is_playing_ = true;
+               }
+               else if (command == L"stop()")
+                       proxy_->stop(0, 0);
+               else if (command == L"next()")
+                       proxy_->next(0);
+               else if (command == L"invoke()")
+                       proxy_->invoke(0, params.at(1));
+               else
+                       return producer_->call(params);
+
+               return make_ready_future<std::wstring>(L"");
+       }
+
+       variable& get_variable(const std::wstring& name) override
+       {
+               if (producer_has_its_own_variables_defined_)
+                       return producer_->get_variable(name);
+
+               auto found = variables_.find(name);
+
+               if (found == variables_.end())
+                       CASPAR_THROW_EXCEPTION(user_error() << msg_info(name + L" not found in scene"));
+
+               return *found->second;
+       }
+
+       const std::vector<std::wstring>& get_variables() const override
+       {
+               return producer_has_its_own_variables_defined_ ? producer_->get_variables() : variable_names_;
+       }
+
+       draw_frame                                                      receive() override                                                                                                                      { return producer_->receive(); }
+       std::wstring                                            print() const override                                                                                                          { return producer_->print(); }
+       void                                                            paused(bool value) override                                                                                                     { producer_->paused(value); }
+       std::wstring                                            name() const override                                                                                                           { return producer_->name(); }
+       uint32_t                                                        frame_number() const override                                                                                           { return producer_->frame_number(); }
+       boost::property_tree::wptree            info() const override                                                                                                           { return producer_->info(); }
+       void                                                            leading_producer(const spl::shared_ptr<frame_producer>& producer) override      { return producer_->leading_producer(producer); }
+       uint32_t                                                        nb_frames() const override                                                                                                      { return producer_->nb_frames(); }
+       draw_frame                                                      last_frame()                                                                                                                            { return producer_->last_frame(); }
+       monitor::subject&                                       monitor_output() override                                                                                                       { return producer_->monitor_output(); }
+       bool                                                            collides(double x, double y) const override                                                                     { return producer_->collides(x, y); }
+       void                                                            on_interaction(const interaction_event::ptr& event)     override                                { return producer_->on_interaction(event); }
+       constraints&                                            pixel_constraints() override                                                                                            { return producer_->pixel_constraints(); }
+private:
+       std::wstring generate_template_data_xml() const
+       {
+               boost::property_tree::wptree document;
+               boost::property_tree::wptree template_data;
+
+               for (auto& parameter_name : variable_names_)
+               {
+                       boost::property_tree::wptree component_data;
+
+                       component_data.add(L"<xmlattr>.id", parameter_name);
+                       component_data.add(L"data.<xmlattr>.id", L"text");
+                       component_data.add(L"data.<xmlattr>.value", variables_.at(parameter_name)->to_string());
+
+                       template_data.add_child(L"componentData", component_data);
+               }
+
+               document.add_child(L"templateData", template_data);
+
+               std::wstringstream xml;
+               static boost::property_tree::xml_writer_settings<std::wstring> NO_INDENTATION_SETTINGS(' ', 0);
+               boost::property_tree::xml_parser::write_xml(xml, document, NO_INDENTATION_SETTINGS);
+               // Necessary hack
+               static std::wstring PROCESSING_INSTRUCTION_TO_REMOVE = L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+               return xml.str().substr(PROCESSING_INSTRUCTION_TO_REMOVE.length());
+       }
+
+       template<typename T>
+       void create_parameter(const std::wstring& name)
+       {
+               auto var = spl::make_shared<core::variable_impl<T>>();
+
+               template_data_xml_.depend_on(var->value());
+               variables_.insert(std::make_pair(name, var));
+               variable_names_.push_back(name);
+       }
+};
+
+void describe_cg_proxy_as_producer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Wraps any CG producer for compatibility with scene producer.");
+       sink.syntax(L"[CG] [template:string] {[param1_type:\"string\",\"number\"] [param1_name:string] {[param2_type:\"string\",\"number\"] [param2_name:string] {...}}}");
+       sink.para()->text(L"Wraps any CG producer for compatibility with scene producer.");
+       sink.para()->text(L"It allows the user to specify what template parameters should be exposed to the parent scene. This is only required for Flash and HTML templates. PSD and Scene templates does this automatically.");
+       sink.para()->text(L"Examples only really usable from within the scene producer implementation:");
+       sink.example(L">> PLAY 1-10 [CG] folder/flas_template string f0 number f1");
+       sink.para()->text(L"...followed by the scene producer setting variables causing the equivalent of a ")->code(L"CG ADD")->text(L". Then the following calls can be made:");
+       sink.example(L">> CALL 1-10 play()");
+       sink.example(L">> CALL 1-10 next()");
+       sink.example(L">> CALL 1-10 invoke() label");
+       sink.example(L">> CALL 1-10 stop()");
+}
+
+spl::shared_ptr<frame_producer> create_cg_proxy_as_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
+{
+       if (!boost::iequals(params.at(0), L"[CG]") || params.size() < 2)
+               return frame_producer::empty();
+
+       auto template_name      = params.at(1);
+       auto producer           = dependencies.cg_registry->create_producer(dependencies, template_name);
+       auto proxy                      = dependencies.cg_registry->get_proxy(producer);
+       auto params2            = params;
+
+       if (proxy == cg_proxy::empty())
+               CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(L"No template with name " + template_name + L" found"));
+
+       // Remove "[CG]" and template_name to only leave the parameter specification part
+       params2.erase(params2.begin(), params2.begin() + 2);
+
+       return spl::make_shared<cg_proxy_as_producer>(std::move(producer), std::move(proxy), template_name, params2);
+}
+
+void init_cg_proxy_as_producer(core::module_dependencies dependencies)
+{
+       dependencies.producer_registry->register_producer_factory(L"CG proxy wrapper", create_cg_proxy_as_producer, describe_cg_proxy_as_producer);
+}
+
 }}
index 93be32c0eee85a1c0de79672b537ad3b8964e37a..9684e94a82f0b8f300466303e7cbe1d61adc2d88 100644 (file)
@@ -32,7 +32,7 @@
 #include <boost/noncopyable.hpp>
 
 namespace caspar { namespace core {
-               
+
 class cg_proxy
 {
 public:
@@ -96,5 +96,6 @@ private:
        spl::shared_ptr<impl> impl_;
 };
 
+void init_cg_proxy_as_producer(core::module_dependencies dependencies);
 
 }}
index 25cd22b4993814f0e233beb9820321794cf5827e..c5ea1807cf909ee2ad513302877e68049dbff145 100644 (file)
@@ -30,6 +30,8 @@
 #include <core/help/util.h>
 #include <core/consumer/syncto/syncto_consumer.h>
 #include <core/producer/text/text_producer.h>
+#include <core/producer/scene/xml_scene_producer.h>
+#include <core/producer/cg_proxy.h>
 
 #include <protocol/amcp/amcp_command_repository.h>
 #include <protocol/amcp/AMCPCommandsImpl.h>
@@ -152,7 +154,7 @@ public:
                out_ << std::endl;
        }
 private:
-       void begin_item(const std::wstring& name) override 
+       void begin_item(const std::wstring& name) override
        {
                out_ << L"==" << name << L"==\n" << std::endl;
        }
@@ -231,13 +233,15 @@ int main(int argc, char** argv)
 
        core::module_dependencies dependencies(system_info_provider_repo, cg_registry, media_info_repo, producer_registry, consumer_registry);
        initialize_modules(dependencies);
-       core::text::init(dependencies);
+       core::init_cg_proxy_as_producer(dependencies);
+       core::scene::init(dependencies);
+       core::syncto::init(dependencies);
 
        generate_amcp_commands_help(*help_repo);
        generate_producers_help(*help_repo);
        generate_consumers_help(*help_repo);
 
        uninitialize_modules();
-       
+
        return 0;
 }
index 763659c29ebff0ed81c035d4dc12af702164ba7d..87b7e105c3303aa203e0fd4f10c1c117a2012554 100644 (file)
@@ -171,6 +171,7 @@ struct server::impl : boost::noncopyable
 
                initialize_modules(dependencies);
                core::text::init(dependencies);
+               core::init_cg_proxy_as_producer(dependencies);
                core::scene::init(dependencies);
                core::syncto::init(dependencies);
                help_repo_->register_item({ L"producer" }, L"Color Producer", &core::describe_color_producer);