]> git.sesse.net Git - casparcg/blobdiff - modules/reroute/producer/reroute_producer.cpp
[channel_producer] #590 Added NO_AUTO_DEINTERLACE parameter to channel route AMCP...
[casparcg] / modules / reroute / producer / reroute_producer.cpp
index e31c00983de429f2f20be2d3f4b39d8a68e7d833..d334a4365e0494e1132503b7c7f9fd53fa25b7ab 100644 (file)
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\r
-*\r
-* CasparCG is free software: you can redistribute it and/or modify\r
-* it under the terms of the GNU General Public License as published by\r
-* the Free Software Foundation, either version 3 of the License, or\r
-* (at your option) any later version.\r
-*\r
-* CasparCG is distributed in the hope that it will be useful,\r
-* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-* GNU General Public License for more details.\r
-*\r
-* You should have received a copy of the GNU General Public License\r
-* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../stdafx.h"\r
-\r
-#include "reroute_producer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/frame/draw_frame.h>\r
-#include <core/frame/frame_factory.h>\r
-#include <core/frame/pixel_format.h>\r
-#include <core/frame/frame.h>\r
-\r
-#include <common/except.h>\r
-#include <common/diagnostics/graph.h>\r
-#include <common/log.h>\r
-#include <common/reactive.h>\r
-\r
-#include <asmlib.h>\r
-\r
-#include <tbb/concurrent_queue.h>\r
-\r
-#include <boost/property_tree/ptree.hpp>\r
-#include <boost/range/algorithm_ext/push_back.hpp>\r
-\r
-#include <queue>\r
-\r
-namespace caspar { namespace reroute {\r
-//             \r
-//class reroute_producer : public reactive::observer<spl::shared_ptr<const core::frame>>\r
-//                                        , public core::frame_producer\r
-//{\r
-//     const spl::shared_ptr<diagnostics::graph>                                                                       graph_;\r
-//     const spl::shared_ptr<core::frame_factory>                                                                      frame_factory_;\r
-//     \r
-//     tbb::concurrent_bounded_queue<std::shared_ptr<const core::frame>>               input_buffer_;\r
-//     std::queue<core::draw_frame>                                                                                            frame_buffer_;\r
-//     uint64_t                                                                                                                                        frame_number_;\r
-//\r
-//     core::draw_frame                                                                                                                        last_frame_;\r
-//\r
-//public:\r
-//     explicit reroute_producer(const spl::shared_ptr<core::frame_factory>& frame_factory) \r
-//             : frame_factory_(frame_factory)\r
-//             , frame_number_(0)\r
-//             , last_frame_(core::draw_frame::empty())\r
-//     {\r
-//             graph_->set_color("late-frame", diagnostics::color(0.6f, 0.3f, 0.3f));\r
-//             graph_->set_color("dropped-frame", diagnostics::color(0.3f, 0.6f, 0.3f));\r
-//             graph_->set_text(print());\r
-//             diagnostics::register_graph(graph_);\r
-//\r
-//             input_buffer_.set_capacity(1);\r
-//     }\r
-//     \r
-//     // observable\r
-//\r
-//     void on_next(const spl::shared_ptr<const core::frame>& frame)\r
-//     {\r
-//             if(!input_buffer_.try_push(frame))\r
-//                     graph_->set_tag("dropped-frame");\r
-//     }\r
-//\r
-//     // frame_producer\r
-//                     \r
-//     core::draw_frame receive(int) override\r
-//     {\r
-//             if(!frame_buffer_.empty())\r
-//             {\r
-//                     auto frame = std::move(frame_buffer_.front());\r
-//                     frame_buffer_.pop();\r
-//                     return last_frame_ = frame;\r
-//             }\r
-//             \r
-//             std::shared_ptr<const core::frame> read_frame;\r
-//             if(!input_buffer_.try_pop(read_frame))\r
-//             {\r
-//                     graph_->set_tag("late-frame");\r
-//                     return core::draw_frame::late();                \r
-//             }\r
-//             \r
-//             frame_number_++;\r
-//             \r
-//             bool double_speed       = std::abs(frame_factory_->video_format_desc().fps / 2.0 - read_frame->frame_rate()) < 0.01;            \r
-//             bool half_speed         = std::abs(read_frame->frame_rate() / 2.0 - frame_factory_->video_format_desc().fps) < 0.01;\r
-//\r
-//             if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
-//                     return receive(0);\r
-//\r
-//             auto frame = frame_factory_->create_frame(this, read_frame->pixel_format_desc());\r
-//\r
-//             A_memcpy(frame->image_data(0).begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
-//             boost::push_back(frame->audio_data(), read_frame->audio_data());\r
-//             \r
-//             auto draw_frame = core::draw_frame(std::move(frame));\r
-//\r
-//             frame_buffer_.push(draw_frame);\r
-//             \r
-//             if(double_speed)        \r
-//                     frame_buffer_.push(draw_frame);\r
-//\r
-//             return receive(0);\r
-//     }       \r
-//\r
-//     core::draw_frame last_frame() const override\r
-//     {\r
-//             return core::draw_frame::still(last_frame_);\r
-//     }\r
-//     \r
-//     std::wstring print() const override\r
-//     {\r
-//             return L"reroute[]";\r
-//     }\r
-//\r
-//     std::wstring name() const override\r
-//     {\r
-//             return L"reroute";\r
-//     }\r
-//\r
-//     boost::property_tree::wptree info() const override\r
-//     {\r
-//             boost::property_tree::wptree info;\r
-//             info.add(L"type", L"rerotue-producer");\r
-//             return info;\r
-//     }\r
-//};\r
-\r
-spl::shared_ptr<core::frame_producer> create_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, core::video_channel& channel)\r
-{\r
-       BOOST_THROW_EXCEPTION(not_implemented());\r
-       //return core::frame_producer::empty();\r
-       //auto producer = spl::make_shared<reroute_producer>(frame_factory);\r
-       //o.subscribe(producer);\r
-       //return core::wrap_producer(producer);\r
-}\r
-\r
-}}
\ No newline at end of file
+/*
+* 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: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../stdafx.h"
+
+#include "reroute_producer.h"
+#include "layer_producer.h"
+#include "channel_producer.h"
+
+#include <common/param.h>
+
+#include <core/producer/frame_producer.h>
+#include <core/video_channel.h>
+#include <core/help/help_sink.h>
+#include <core/help/help_repository.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/range/algorithm/find_if.hpp>
+
+namespace caspar { namespace reroute {
+
+void describe_producer(core::help_sink& sink, const core::help_repository& repository)
+{
+       sink.short_description(L"Reroutes a complete channel or a layer to another layer.");
+       sink.syntax(L"route://[source_channel:int]{-[source_layer:int]} {FRAMES_DELAY [frames_delay:int]} {[no_auto_deinterlace:NO_AUTO_DEINTERLACE]}");
+       sink.para()->text(L"Reroutes the composited video of a channel or the untransformed video of a layer.");
+       sink.para()
+               ->text(L"If ")->code(L"source_layer")->text(L" is specified, only the video of the source layer is rerouted. ")
+               ->text(L"If on the other hand only ")->code(L"source_channel")->text(L" is specified, the video of the complete channel is rerouted.");
+       sink.para()
+               ->text(L"An optional additional delay can be specified with the ")->code(L"frames_delay")
+               ->text(L" parameter.");
+       sink.para()
+               ->text(L"For channel routing an optional ")->code(L"no_auto_deinterlace")
+               ->text(L" parameter can be specified, when performance is more important than good quality output.");
+       sink.para()->text(L"Examples:");
+       sink.example(L">> PLAY 1-10 route://1-11", L"Play the contents of layer 1-11 on layer 1-10 as well.");
+       sink.example(L">> PLAY 1-10 route://2", L"Play the composited contents of channel 2 on layer 1-10 as well.");
+       sink.example(L">> PLAY 1-10 route://2 NO_AUTO_DEINTERLACE");
+       sink.example(
+               L">> MIXER 1-10 FILL 0.02 0.01 0.9 0.9\n"
+               L">> PLAY 1-10 route://1\n"
+               L">> PLAY 1-9 AMB LOOP", L"Play the composited contents of channel 1 on layer 1-10. Since the source and destination channel is the same, an \"infinity\" effect is created.");
+       sink.example(L">> PLAY 1-10 route://1-11 FRAMES_DELAY 10", L"Play the contents of layer 1-11 on layer 1-10 as well with an added 10 frames delay.");
+       sink.para()
+               ->text(L"Always expect a few frames delay on the routed-to layer in addition to the optionally specified ")
+               ->code(L"frames_delay")->text(L" parameter.");
+}
+
+spl::shared_ptr<core::frame_producer> create_producer(
+               const core::frame_producer_dependencies& dependencies,
+               const std::vector<std::wstring>& params)
+{
+       static const std::wstring PREFIX = L"route://";
+
+       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"))
+       {
+               return core::frame_producer::empty();
+       }
+
+       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;
+
+       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);
+
+       auto found_channel = boost::find_if(dependencies.channels, [=](spl::shared_ptr<core::video_channel> ch) { return ch->index() == channel_id; });
+
+       if (found_channel == dependencies.channels.end())
+               CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"No channel with id " + boost::lexical_cast<std::wstring>(channel_id)));
+
+       auto params2 = params;
+       params2.erase(params2.begin());
+
+       auto frames_delay                       = get_param(L"FRAMES_DELAY", params2, 0);
+       bool no_auto_deinterlace        = contains_param(L"NO_AUTO_DEINTERLACE", params2);
+
+       if (has_layer_spec)
+       {
+               auto layer = boost::lexical_cast<int>(channel_layer_spec.substr(dash + 1));
+
+               return create_layer_producer(*found_channel, layer, frames_delay, dependencies.format_desc);
+       }
+       else
+       {
+               return create_channel_producer(dependencies, *found_channel, frames_delay, no_auto_deinterlace);
+       }
+}
+
+}}