]> git.sesse.net Git - casparcg/commitdiff
* Enforce help descriptions for consumers in code.
authorHelge Norberg <helge.norberg@svt.se>
Tue, 11 Aug 2015 17:55:56 +0000 (19:55 +0200)
committerHelge Norberg <helge.norberg@svt.se>
Tue, 11 Aug 2015 17:55:56 +0000 (19:55 +0200)
* Added HELP CONSUMER command to list available consumers and get help for them.
* Updated generate_docs.cpp to also include a wiki page for the consumers.

28 files changed:
core/consumer/frame_consumer.cpp
core/consumer/frame_consumer.h
modules/bluefish/bluefish.cpp
modules/bluefish/consumer/bluefish_consumer.cpp
modules/bluefish/consumer/bluefish_consumer.h
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/consumer/decklink_consumer.h
modules/decklink/decklink.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.h
modules/ffmpeg/consumer/streaming_consumer.cpp
modules/ffmpeg/consumer/streaming_consumer.h
modules/ffmpeg/ffmpeg.cpp
modules/image/consumer/image_consumer.cpp
modules/image/consumer/image_consumer.h
modules/image/image.cpp
modules/newtek/consumer/newtek_ivga_consumer.cpp
modules/newtek/consumer/newtek_ivga_consumer.h
modules/newtek/newtek.cpp
modules/oal/consumer/oal_consumer.cpp
modules/oal/consumer/oal_consumer.h
modules/oal/oal.cpp
modules/screen/consumer/screen_consumer.cpp
modules/screen/consumer/screen_consumer.h
modules/screen/screen.cpp
protocol/amcp/AMCPCommandsImpl.cpp
shell/generate_docs.cpp
shell/server.cpp

index 07d916d05c87b0d81a8dd9ffafaaa7b556167e57..aacf0fd090b5236f152734b123d2ede97bfb0a19 100644 (file)
@@ -39,18 +39,25 @@ namespace caspar { namespace core {
 
 struct frame_consumer_registry::impl
 {
-       std::vector<consumer_factory_t> consumer_factories;
-       std::map<std::wstring, preconfigured_consumer_factory_t> preconfigured_consumer_factories;
+       std::vector<consumer_factory_t>                                                         consumer_factories;
+       std::map<std::wstring, preconfigured_consumer_factory_t>        preconfigured_consumer_factories;
+       spl::shared_ptr<help_repository>                                                        help_repo;
+
+       impl(spl::shared_ptr<help_repository> help_repo)
+               : help_repo(std::move(help_repo))
+       {
+       }
 };
 
-frame_consumer_registry::frame_consumer_registry()
-       : impl_(new impl)
+frame_consumer_registry::frame_consumer_registry(spl::shared_ptr<help_repository> help_repo)
+       : impl_(new impl(std::move(help_repo)))
 {
 }
 
-void frame_consumer_registry::register_consumer_factory(const consumer_factory_t& factory)
+void frame_consumer_registry::register_consumer_factory(const std::wstring& name, const consumer_factory_t& factory, const help_item_describer& describer)
 {
        impl_->consumer_factories.push_back(factory);
+       impl_->help_repo->register_item({ L"consumer" }, std::move(name), describer);
 }
 
 void frame_consumer_registry::register_preconfigured_consumer_factory(
index fbda2c4605929c61da88c79c1393851276d266af..ed1f6f093d64b2b141c0a83dc304495491baab3b 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "../monitor/monitor.h"
 #include "../fwd.h"
+#include "../help/help_repository.h"
 
 #include <common/memory.h>
 #include <common/future_fwd.h>
@@ -80,8 +81,8 @@ typedef std::function<spl::shared_ptr<frame_consumer>(
 class frame_consumer_registry : boost::noncopyable
 {
 public:
-       frame_consumer_registry();
-       void register_consumer_factory(const consumer_factory_t& factory);
+       frame_consumer_registry(spl::shared_ptr<help_repository> help_repo);
+       void register_consumer_factory(const std::wstring& name, const consumer_factory_t& factory, const help_item_describer& describer);
        void register_preconfigured_consumer_factory(
                        const std::wstring& element_name,
                        const preconfigured_consumer_factory_t& factory);
index d2ecabf835f3d14d047ecbd88d0d1064a5a49533..8fb124efeb6eb2d181cacd024b68d5197580448a 100644 (file)
@@ -84,7 +84,7 @@ void init(core::module_dependencies dependencies)
        }
        catch(...){}
 
-       dependencies.consumer_registry->register_consumer_factory(create_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"Bluefish Consumer", create_consumer, describe_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"bluefish", create_preconfigured_consumer);
        dependencies.system_info_provider_repo->register_system_info_provider([](boost::property_tree::wptree& info)
        {
index d85f934b8065755fa53a73b6556b646c7b0d311c..d5c06a74e76fd8fc3c7c8a04922bd35b0b8127ba 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <core/video_format.h>
 #include <core/frame/frame.h>
+#include <core/help/help_repository.h>
+#include <core/help/help_sink.h>
 
 #include <common/executor.h>
 #include <common/diagnostics/graph.h>
@@ -373,6 +375,28 @@ public:
        }
 };     
 
+
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Sends video on an SDI output using Bluefish video cards.");
+       sink.syntax(L"BLUEFISH {[device_index:int]|1} {[embedded_audio:EMBEDDED_AUDIO]} {[key_only:KEY_ONLY]}");
+       sink.para()
+               ->text(L"Sends video on an SDI output using Bluefish video cards. Multiple video cards can be ")
+               ->text(L"installed in the same machine and used at the same time, they will be addressed via ")
+               ->text(L"different ")->code(L"device_index")->text(L" parameters.");
+       sink.para()->text(L"Specify ")->code(L"embedded_audio")->text(L" to embed audio into the SDI signal.");
+       sink.para()
+               ->text(L"Specifying ")->code(L"key_only")->text(L" will extract only the alpha channel from the ")
+               ->text(L"channel. This is useful when you have two SDI video cards, and neither has native support ")
+               ->text(L"for separate fill/key output");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 BLUEFISH", L"uses the default device_index of 1.");
+       sink.example(L">> ADD 1 BLUEFISH 2", L"for device_index 2.");
+       sink.example(
+               L">> ADD 1 BLUEFISH 1 EMBEDDED_AUDIO\n"
+               L">> ADD 1 BLUEFISH 2 KEY_ONLY", L"uses device with index 1 as fill output with audio and device with index 2 as key output.");
+}
+
 spl::shared_ptr<core::frame_consumer> create_consumer(
                const std::vector<std::wstring>& params, core::interaction_sink*)
 {
index 855974e2182ecae5b407172ef91ced05c9b296a4..3c4ec6dbb9b61353f00e8da73190ed109bdb20fd 100644 (file)
@@ -31,6 +31,7 @@
 
 namespace caspar { namespace bluefish {
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo);
 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(
index 81a35fad7153153b6b2b9b64d26e2bfeca2b1463..36abd464ce056691c74041d39e25b95d478b227d 100644 (file)
 
 #include <core/frame/frame.h>
 #include <core/mixer/audio/audio_mixer.h>
+#include <core/consumer/frame_consumer.h>
+#include <core/diagnostics/call_context.h>
+#include <core/help/help_sink.h>
+#include <core/help/help_repository.h>
 
 #include <common/executor.h>
 #include <common/lock.h>
@@ -41,9 +45,6 @@
 #include <common/timer.h>
 #include <common/param.h>
 
-#include <core/consumer/frame_consumer.h>
-#include <core/diagnostics/call_context.h>
-
 #include <tbb/concurrent_queue.h>
 
 #include <common/assert.h>
@@ -578,6 +579,34 @@ public:
        }
 };     
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Sends video on an SDI output using Blackmagic Decklink video cards.");
+       sink.syntax(L"DECKLINK "
+                               L"{[device_index:int]|1} "
+                               L"{[keyer:INTERNAL_KEY,EXTERNAL_KEY]} "
+                               L"{[low_latency:LOW_LATENCY]} "
+                               L"{[embedded_audio:EMBEDDED_AUDIO]} "
+                               L"{[key_only:KEY_ONLY]}");
+       sink.para()->text(L"Sends video on an SDI output using Blackmagic Decklink video cards.");
+       sink.definitions()
+               ->item(L"device_index", L"The Blackmagic video card to use (See Blackmagic control panel for card order). Default is 1.")
+               ->item(L"keyer", L"If given tries to enable either internal or external keying. Not all Blackmagic cards supports this.")
+               ->item(L"low_latency", L"Tries to enable low latency if given.")
+               ->item(L"embedded_audio", L"Embeds the audio into the SDI signal if given.")
+               ->item(L"key_only",
+                               L" will extract only the alpha channel from the "
+                               L"channel. This is useful when you have two SDI video cards, and neither has native support "
+                               L"for separate fill/key output");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 DECKLINK", L"for using the default device_index of 1.");
+       sink.example(L">> ADD 1 DECKLINK 2", L"uses device_index 2.");
+       sink.example(L">> ADD 1 DECKLINK 1 EXTERNAL_KEY EMBEDDED_AUDIO");
+       sink.example(
+               L">> ADD 1 DECKLINK 1 EMBEDDED_AUDIO\n"
+               L">> ADD 1 DECKLINK 2 KEY_ONLY", L"uses device with index 1 as fill output with audio and device with index 2 as key output.");
+}
+
 spl::shared_ptr<core::frame_consumer> create_consumer(
                const std::vector<std::wstring>& params, core::interaction_sink*)
 {
index 652e8a6f39a849bbd8678f535b7d8a814cd700a4..9c0de882f05e50bc7f911f0cfa6e20d81833163a 100644 (file)
@@ -32,6 +32,7 @@
 
 namespace caspar { namespace decklink {
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo);
 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(
index 8a2aa54ef93af39918cc3b42a2a8728306bfb561..db1d639cd1a6a6811bdc39bea8d63efbd5b9621b 100644 (file)
@@ -82,7 +82,7 @@ std::vector<std::wstring> device_list()
 
 void init(core::module_dependencies dependencies)
 {
-       dependencies.consumer_registry->register_consumer_factory(create_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"Decklink Consumer", create_consumer, describe_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"decklink", create_preconfigured_consumer);
        dependencies.producer_registry->register_producer_factory(L"Decklink Producer", create_producer, describe_producer);
        dependencies.system_info_provider_repo->register_system_info_provider([](boost::property_tree::wptree& info)
index 5c0b02949207b4266ea1790eeb12b747f88957cd..44c6c2b392bc40cbe61d0cab014a7acb31c4e06d 100644 (file)
@@ -31,6 +31,8 @@
 #include <core/mixer/audio/audio_util.h>
 #include <core/consumer/frame_consumer.h>
 #include <core/video_format.h>
+#include <core/help/help_repository.h>
+#include <core/help/help_sink.h>
 
 #include <common/array.h>
 #include <common/env.h>
@@ -847,7 +849,26 @@ public:
        {
                return consumer_->monitor_output();
        }
-};     
+};
+
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Can record a channel to a file supported by FFMpeg.");
+       sink.syntax(L"FILE [filename:string] {-[ffmpeg_param1:string] [value1:string] {-[ffmpeg_param2:string] [value2:string] {...}}} {[separate_key:SEPARATE_KEY]}");
+       sink.para()->text(L"Can record a channel to a file supported by FFMpeg.");
+       sink.definitions()
+               ->item(L"filename", L"The filename under the media folder including the extension (decides which kind of container format that will be used).")
+               ->item(L"ffmpeg_paramX", L"A parameter supported by FFMpeg. For example vcodec or acodec etc.")
+               ->item(L"separate_key", L"If defined will create two files simultaneously -- One for fill and one for key (_A will be appended).")
+               ;
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 FILE output.mov -vcodec dnxhd");
+       sink.example(L">> ADD 1 FILE output.mov -vcodec prores");
+       sink.example(L">> ADD 1 FILE output.mov -vcodec dvvideo");
+       sink.example(L">> ADD 1 FILE output.mov - vcodec libx264 -preset ultrafast -tune fastdecode -crf 25");
+       sink.example(L">> ADD 1 FILE output.mov -vcodec dnxhd SEPARATE_KEY", L"for creating output.mov with fill and output_A.mov with key/alpha");
+}
+
 spl::shared_ptr<core::frame_consumer> create_consumer(
                const std::vector<std::wstring>& params, core::interaction_sink*)
 {
index 931f1a641456cf9aae6537c45e7c5ef299bef762..ac27b94e915b1d846d431693e043e71098844aaa 100644 (file)
@@ -32,6 +32,7 @@
 
 namespace caspar { namespace ffmpeg {
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo);
 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*);
 
index 77543a10fa32f7d0804a7dd708dfd2ff54c1b823..fafb6f03e2d009ecde85d83d2b3ba3c1eb510ca0 100644 (file)
@@ -16,6 +16,8 @@
 #include <core/frame/frame.h>
 #include <core/video_format.h>
 #include <core/monitor/monitor.h>
+#include <core/help/help_repository.h>
+#include <core/help/help_sink.h>
 
 #include <boost/noncopyable.hpp>
 #include <boost/rational.hpp>
@@ -1248,7 +1250,19 @@ private:
                return result;
        }
 };
-       
+
+void describe_streaming_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"For streaming the contents of a channel using FFMpeg.");
+       sink.syntax(L"STREAM [url:string] {-[ffmpeg_param1:string] [value1:string] {-[ffmpeg_param2:string] [value2:string] {...}}}");
+       sink.para()->text(L"For streaming the contents of a channel using FFMpeg");
+       sink.definitions()
+               ->item(L"url", L"The stream URL to create/stream to.")
+               ->item(L"ffmpeg_paramX", L"A parameter supported by FFMpeg. For example vcodec or acodec etc.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 STREAM udp://<client_ip_address>:9250 -format mpegts -vcodec libx264 -crf 25 -tune zerolatency -preset ultrafast");
+}
+
 spl::shared_ptr<core::frame_consumer> create_streaming_consumer(
                const std::vector<std::wstring>& params, core::interaction_sink*)
 {       
index 0733ab8a484e17f6151fb5ac202f06baee051856..2663cf4f152c9b6a310261e78d55b11d657544b8 100644 (file)
@@ -10,7 +10,8 @@
 #include <vector>
 
 namespace caspar { namespace ffmpeg {
-       
+
+void describe_streaming_consumer(core::help_sink& sink, const core::help_repository& repo);
 spl::shared_ptr<core::frame_consumer> create_streaming_consumer(
                const std::vector<std::wstring>& params, core::interaction_sink*);
 spl::shared_ptr<core::frame_consumer> create_preconfigured_streaming_consumer(
index 195c0239ec609788a0caff402061484306d11346..7a151f05b62879d6754560a5e736c08c307f6e84 100644 (file)
@@ -247,8 +247,8 @@ void init(core::module_dependencies dependencies)
     avformat_network_init();
     avcodec_register_all();
        
-       dependencies.consumer_registry->register_consumer_factory(create_consumer);
-       dependencies.consumer_registry->register_consumer_factory(create_streaming_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"FFMpeg Consumer", create_consumer, describe_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"Streaming Consumer",  create_streaming_consumer, describe_streaming_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"file", create_preconfigured_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"stream", create_preconfigured_streaming_consumer);
        dependencies.producer_registry->register_producer_factory(L"FFmpeg Producer", create_producer, describe_producer);
index 2e91603615f7e8b0a28461f21e7a2031dc154047..bfc18c524c80bd4db40adf0b69eba2a88d4001ad 100644 (file)
@@ -31,6 +31,8 @@
 #include <core/consumer/frame_consumer.h>
 #include <core/video_format.h>
 #include <core/frame/frame.h>
+#include <core/help/help_sink.h>
+#include <core/help/help_repository.h>
 
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/thread.hpp>
 
 namespace caspar { namespace image {
 
-       void write_cropped_png(
+void write_cropped_png(
                const core::const_frame& frame,
                const core::video_format_desc& format_desc,
                const boost::filesystem::path& output_file,
                int width,
                int height)
-       {
-               auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Allocate(width, height, 32), FreeImage_Unload);
-               image_view<bgra_pixel> destination_view(FreeImage_GetBits(bitmap.get()), width, height);
-               image_view<bgra_pixel> complete_frame(const_cast<uint8_t*>(frame.image_data().begin()), format_desc.width, format_desc.height);
-               auto thumbnail_view = complete_frame.subview(0, 0, width, height);
-
-               std::copy(thumbnail_view.begin(), thumbnail_view.end(), destination_view.begin());
-               FreeImage_FlipVertical(bitmap.get());
-               FreeImage_SaveU(FIF_PNG, bitmap.get(), output_file.wstring().c_str(), 0);
-       }
+{
+       auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Allocate(width, height, 32), FreeImage_Unload);
+       image_view<bgra_pixel> destination_view(FreeImage_GetBits(bitmap.get()), width, height);
+       image_view<bgra_pixel> complete_frame(const_cast<uint8_t*>(frame.image_data().begin()), format_desc.width, format_desc.height);
+       auto thumbnail_view = complete_frame.subview(0, 0, width, height);
+
+       std::copy(thumbnail_view.begin(), thumbnail_view.end(), destination_view.begin());
+       FreeImage_FlipVertical(bitmap.get());
+       FreeImage_SaveU(FIF_PNG, bitmap.get(), output_file.wstring().c_str(), 0);
+}
 
 struct image_consumer : public core::frame_consumer
 {
@@ -150,6 +152,18 @@ public:
        }
 };
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Writes a single PNG snapshot of a video channel.");
+       sink.syntax(L"IMAGE {[filename:string]|yyyyMMddTHHmmss}");
+       sink.para()
+               ->text(L"Writes a single PNG snapshot of a video channel. ")->code(L".png")->text(L" will be appended to ")
+               ->code(L"filename")->text(L". The PNG image will be stored under the ")->code(L"media")->text(L" folder.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 IMAGE screenshot", L"creating media/screenshot.png");
+       sink.example(L">> ADD 1 IMAGE", L"creating media/20130228T210946.png if the current time is 2013-02-28 21:09:46.");
+}
+
 spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if (params.size() < 1 || !boost::iequals(params.at(0), L"IMAGE"))
index d9e8bc522bd0d69eef189fc9816caf876a7b86aa..fc47c62543d371783c5bd8293a4b08efb88ae4a5 100644 (file)
@@ -42,6 +42,7 @@ void write_cropped_png(
                int width,
                int height);
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo);
 spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, struct core::interaction_sink*);
 
 }}
index b0d7438a65975f28758ea79dfabd9378ab5f8166..ea27ca9cec25e2199293155ec29370656636fa3d 100644 (file)
@@ -50,7 +50,7 @@ void init(core::module_dependencies dependencies)
        dependencies.producer_registry->register_producer_factory(L"Image Scroll Producer", create_scroll_producer, describe_scroll_producer);
        dependencies.producer_registry->register_producer_factory(L"Image Producer", create_producer, describe_producer);
        dependencies.producer_registry->register_thumbnail_producer_factory(create_thumbnail_producer);
-       dependencies.consumer_registry->register_consumer_factory(create_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"Image Consumer", create_consumer, describe_consumer);
        dependencies.media_info_repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
        {
                if (extension == L".TGA"
index 2735adb6d08e8644abfd69fa7b1a3b2e8f3a2690..ce9111c2177a1377452ddb083dac3914bb423bcc 100644 (file)
@@ -28,6 +28,8 @@
 #include <core/frame/frame.h>
 #include <core/mixer/audio/audio_util.h>
 #include <core/monitor/monitor.h>
+#include <core/help/help_sink.h>
+#include <core/help/help_repository.h>
 
 #include <common/assert.h>
 #include <common/executor.h>
@@ -171,6 +173,17 @@ public:
        }
 };     
 
+void describe_ivga_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"A consumer for streaming a channel to a NewTek TriCaster via iVGA/AirSend protocol.");
+       sink.syntax(L"NEWTEK_IVGA {[dont_provide_sync:DONT_PROVIDE_SYNC]}");
+       sink.para()->text(L"A consumer for streaming a channel to a NewTek TriCaster via iVGA/AirSend protocol.");
+       sink.para()->text(L"If ")->code(L"dont_provide_sync")->text(L" is specified, the consumer will not genlock the channel.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 NEWTEK_IVGA");
+       sink.example(L">> ADD 1 NEWTEK_IVGA DONT_PROVIDE_SYNC");
+}
+
 spl::shared_ptr<core::frame_consumer> create_ivga_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if (params.size() < 1 || !boost::iequals(params.at(0), L"NEWTEK_IVGA"))
index ea8bd23dd557812ea3865012790f7d135d3b6598..fc41ca726c84e5bd3a7b913c314027f3e813b539 100644 (file)
@@ -31,6 +31,7 @@
 
 namespace caspar { namespace newtek {
 
+void describe_ivga_consumer(core::help_sink& sink, const core::help_repository& repo);
 spl::shared_ptr<core::frame_consumer> create_ivga_consumer(const std::vector<std::wstring>& params, core::interaction_sink*);
 spl::shared_ptr<core::frame_consumer> create_preconfigured_ivga_consumer(const boost::property_tree::wptree& ptree, core::interaction_sink*);
 
index 15ffe1801480eec4ae4ca9dc8f1c7e49499747ca..9fa9b57dfd8b159135c8f394142c6b6e776ead35 100644 (file)
@@ -32,8 +32,7 @@ void init(core::module_dependencies dependencies)
 {
        try
        {
-               if (airsend::is_available())
-                       dependencies.consumer_registry->register_consumer_factory(create_ivga_consumer);
+               dependencies.consumer_registry->register_consumer_factory(L"iVGA Consumer", create_ivga_consumer, describe_ivga_consumer);
                dependencies.system_info_provider_repo->register_system_info_provider([](boost::property_tree::wptree& info)
                {
                        info.add(L"system.newtek-ivga.version", airsend::is_available()
index f9d4aa8706f125d59fb9fb579b954ab7cd1a59b3..cc5e559bef9ebc944630afce4885131f5ef4cd8f 100644 (file)
@@ -34,6 +34,8 @@
 #include <core/mixer/audio/audio_util.h>
 #include <core/mixer/audio/audio_mixer.h>
 #include <core/video_format.h>
+#include <core/help/help_sink.h>
+#include <core/help/help_repository.h>
 
 #include <boost/circular_buffer.hpp>
 #include <boost/lexical_cast.hpp>
@@ -261,6 +263,15 @@ public:
        }
 };
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"A system audio consumer.");
+       sink.syntax(L"AUDIO");
+       sink.para()->text(L"Uses the system's default audio playback device.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 AUDIO");
+}
+
 spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink*)
 {
        if(params.size() < 1 || !boost::iequals(params.at(0), L"AUDIO"))
index c486b24cfc1fa3d8c19548eca263c18263491a59..abb7b7c32c00b5e79046ad4459a0c0381aaef980 100644 (file)
@@ -31,6 +31,7 @@
 
 namespace caspar { namespace oal {
        
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo);
 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(
index ac3d79d1dba6e239d27cecab5b2929ac49751270..ee583a77ec4396625697362c4efe586d22c70bc7 100644 (file)
@@ -29,7 +29,7 @@ namespace caspar { namespace oal {
 
 void init(core::module_dependencies dependencies)
 {
-       dependencies.consumer_registry->register_consumer_factory(create_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"System Audio Consumer", create_consumer, describe_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"system-audio", create_preconfigured_consumer);
 }
 
index e3053471f316f6ec8e9a4f1147c246d9f8cbb0a0..2582350c01fc87fbd5ca3f24e770f5d763d149c6 100644 (file)
@@ -44,6 +44,8 @@
 #include <core/frame/frame.h>
 #include <core/consumer/frame_consumer.h>
 #include <core/interaction/interaction_sink.h>
+#include <core/help/help_sink.h>
+#include <core/help/help_repository.h>
 
 #include <boost/circular_buffer.hpp>
 #include <boost/lexical_cast.hpp>
@@ -646,6 +648,31 @@ public:
        }
 };     
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo)
+{
+       sink.short_description(L"Displays the contents of a channel on screen using OpenGL.");
+       sink.syntax(
+                       L"SCREEN "
+                       L"{[screen_index:int]|1} "
+                       L"{[fullscreen:FULLSCREEN]} "
+                       L"{[key_only:KEY_ONLY]} "
+                       L"{[non_interactive:NON_INTERACTIVE]} "
+                       L"{[no_auto_deinterlace:NO_AUTO_DEINTERLACE]} "
+                       L"{NAME [name:string]}");
+       sink.para()->text(L"Displays the contents of a channel on screen using OpenGL.");
+       sink.definitions()
+               ->item(L"screen_index", L"Determines which screen the channel should be displayed on. Defaults to 1.")
+               ->item(L"fullscreen", L"If specified opens the window in fullscreen.")
+               ->item(L"key_only", L"Only displays the alpha channel of the video channel if specified.")
+               ->item(L"non_interactive", L"If specified does not send mouse input to producers on the video channel.")
+               ->item(L"no_auto_deinterlace", L"If the video mode of the channel is an interlaced mode, specifying this will turn of deinterlacing.")
+               ->item(L"name", L"Optionally specifies a name of the window to show.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> ADD 1 SCREEN", L"opens a screen consumer on the default screen.");
+       sink.example(L">> ADD 1 SCREEN 2", L"opens a screen consumer on the screen 2.");
+       sink.example(L">> ADD 1 SCREEN 1 FULLSCREEN", L"opens a screen consumer in fullscreen on screen 1.");
+}
+
 spl::shared_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params, core::interaction_sink* sink)
 {
        if (params.size() < 1 || !boost::iequals(params.at(0), L"SCREEN"))
index c443a79befae5daf5199197b1e8fdc6b58079c00..f4293c1f3ef6c4fe224b57d4eaff7e85808b6f20 100644 (file)
@@ -30,6 +30,7 @@
 
 namespace caspar { namespace screen {
 
+void describe_consumer(core::help_sink& sink, const core::help_repository& repo);
 spl::shared_ptr<core::frame_consumer> create_consumer(
                const std::vector<std::wstring>& params,
                core::interaction_sink* sink);
index ef670950ad395961c0ddba3f028635f7c3447dde..c413aae388d695246c0d07271f758e4bca2e1283 100644 (file)
@@ -29,7 +29,7 @@ namespace caspar { namespace screen {
 
 void init(core::module_dependencies dependencies)
 {
-       dependencies.consumer_registry->register_consumer_factory(create_consumer);
+       dependencies.consumer_registry->register_consumer_factory(L"Screen Consumer", create_consumer, describe_consumer);
        dependencies.consumer_registry->register_preconfigured_consumer_factory(L"screen", create_preconfigured_consumer);
 }
 
index a602b16a3c35f4c86ef8360f8b8bd3211bd34205..0e58ac7454cd0dec5ed9b54523cee25e62df898a 100644 (file)
@@ -1920,7 +1920,7 @@ std::wstring mixer_grid_command(command_context& ctx)
 void mixer_commit_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Commit all deferred mixer transforms.");
-       sink.syntax(L"MIXER [video_channel:int]{-[layer:int]|-0} COMMIT");
+       sink.syntax(L"MIXER [video_channel:int] COMMIT");
        sink.para()->text(L"Commits all deferred mixer transforms on the specified channel. This ensures that all animations start at the same exact frame.");
        sink.para()->text(L"Examples:");
        sink.example(
@@ -2566,6 +2566,23 @@ std::wstring help_producer_command(command_context& ctx)
                return create_help_details(L"HELP PRODUCER", ctx, { L"producer" });
 }
 
+void help_consumer_describer(core::help_sink& sink, const core::help_repository& repository)
+{
+       sink.short_description(L"Show online help for consumers.");
+       sink.syntax(LR"(HELP CONSUMER {[consumer:string]})");
+       sink.para()->text(LR"(Shows online help for a specific consumer or a list of all consumers.)");
+       sink.example(L">> HELP CONSUMER", L"Shows a list of consumers.");
+       sink.example(L">> HELP CONSUMER Decklink Consumer", L"Shows a detailed description of the Decklink Consumer.");
+}
+
+std::wstring help_consumer_command(command_context& ctx)
+{
+       if (ctx.parameters.size() == 0)
+               return create_help_list(L"HELP CONSUMER", ctx, { L"consumer" });
+       else
+               return create_help_details(L"HELP CONSUMER", ctx, { L"consumer" });
+}
+
 void bye_describer(core::help_sink& sink, const core::help_repository& repo)
 {
        sink.short_description(L"Disconnect the session.");
@@ -2740,6 +2757,7 @@ void register_commands(amcp_command_repository& repo)
        repo.register_command(                  L"Query Commands",              L"RESTART",                                     restart_describer,                                      restart_command,                                0);
        repo.register_command(                  L"Query Commands",              L"HELP",                                        help_describer,                                         help_command,                                   0);
        repo.register_command(                  L"Query Commands",              L"HELP PRODUCER",                       help_producer_describer,                        help_producer_command,                  0);
+       repo.register_command(                  L"Query Commands",              L"HELP CONSUMER",                       help_consumer_describer,                        help_consumer_command,                  0);
 }
 
 }      //namespace amcp
index cbc7ccccc46e262fa0303bb8fba063d05eae78f8..da6ff11adaa924bbefeb1dd850ece76e0cd42931 100644 (file)
@@ -182,6 +182,17 @@ void generate_producers_help(const core::help_repository& help_repo)
        file.flush();
 }
 
+void generate_consumers_help(const core::help_repository& help_repo)
+{
+       boost::filesystem::wofstream file(L"consumers_help.wiki");
+       mediawiki_help_sink sink(file);
+
+       sink.start_section(L"Consumers (Output Modules)");
+       help_repo.help({ L"consumer" }, sink);
+
+       file.flush();
+}
+
 int main(int argc, char** argv)
 {
        env::configure(L"casparcg.config");
@@ -190,7 +201,7 @@ int main(int argc, char** argv)
        auto media_info_repo = core::create_in_memory_media_info_repository();
        spl::shared_ptr<core::help_repository> help_repo;
        auto producer_registry = spl::make_shared<core::frame_producer_registry>(help_repo);
-       spl::shared_ptr<core::frame_consumer_registry> consumer_registry;
+       auto consumer_registry = spl::make_shared<core::frame_consumer_registry>(help_repo);
        std::promise<bool> shutdown_server_now;
        protocol::amcp::amcp_command_repository repo(
                        { },
@@ -211,6 +222,7 @@ int main(int argc, char** argv)
 
        generate_amcp_commands_help(*help_repo);
        generate_producers_help(*help_repo);
+       generate_consumers_help(*help_repo);
 
        uninitialize_modules();
        
index daee0a671f00ca09eeaba037e4001b0fff12f285..04897d48e6ba8cdda14422b7c3155f8ab238ac57 100644 (file)
@@ -106,6 +106,7 @@ struct server::impl : boost::noncopyable
                , osc_client_(io_service_manager_.service())
                , media_info_repo_(create_in_memory_media_info_repository())
                , producer_registry_(spl::make_shared<core::frame_producer_registry>(help_repo_))
+               , consumer_registry_(spl::make_shared<core::frame_consumer_registry>(help_repo_))
                , shutdown_server_now_(shutdown_server_now)
        {
                running_ = false;