]> git.sesse.net Git - casparcg/blob - 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
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../stdafx.h"
23
24 #include "reroute_producer.h"
25 #include "layer_producer.h"
26 #include "channel_producer.h"
27
28 #include <common/param.h>
29
30 #include <core/producer/frame_producer.h>
31 #include <core/video_channel.h>
32 #include <core/help/help_sink.h>
33 #include <core/help/help_repository.h>
34
35 #include <boost/algorithm/string.hpp>
36 #include <boost/range/algorithm/find_if.hpp>
37
38 namespace caspar { namespace reroute {
39
40 void describe_producer(core::help_sink& sink, const core::help_repository& repository)
41 {
42         sink.short_description(L"Reroutes a complete channel or a layer to another layer.");
43         sink.syntax(L"route://[source_channel:int]{-[source_layer:int]} {FRAMES_DELAY [frames_delay:int]} {[no_auto_deinterlace:NO_AUTO_DEINTERLACE]}");
44         sink.para()->text(L"Reroutes the composited video of a channel or the untransformed video of a layer.");
45         sink.para()
46                 ->text(L"If ")->code(L"source_layer")->text(L" is specified, only the video of the source layer is rerouted. ")
47                 ->text(L"If on the other hand only ")->code(L"source_channel")->text(L" is specified, the video of the complete channel is rerouted.");
48         sink.para()
49                 ->text(L"An optional additional delay can be specified with the ")->code(L"frames_delay")
50                 ->text(L" parameter.");
51         sink.para()
52                 ->text(L"For channel routing an optional ")->code(L"no_auto_deinterlace")
53                 ->text(L" parameter can be specified, when performance is more important than good quality output.");
54         sink.para()->text(L"Examples:");
55         sink.example(L">> PLAY 1-10 route://1-11", L"Play the contents of layer 1-11 on layer 1-10 as well.");
56         sink.example(L">> PLAY 1-10 route://2", L"Play the composited contents of channel 2 on layer 1-10 as well.");
57         sink.example(L">> PLAY 1-10 route://2 NO_AUTO_DEINTERLACE");
58         sink.example(
59                 L">> MIXER 1-10 FILL 0.02 0.01 0.9 0.9\n"
60                 L">> PLAY 1-10 route://1\n"
61                 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.");
62         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.");
63         sink.para()
64                 ->text(L"Always expect a few frames delay on the routed-to layer in addition to the optionally specified ")
65                 ->code(L"frames_delay")->text(L" parameter.");
66 }
67
68 spl::shared_ptr<core::frame_producer> create_producer(
69                 const core::frame_producer_dependencies& dependencies,
70                 const std::vector<std::wstring>& params)
71 {
72         static const std::wstring PREFIX = L"route://";
73
74         if (params.empty() ||
75                 !boost::starts_with(params.at(0), PREFIX) ||
76                 boost::ends_with(params.at(0), L"_A") ||
77                 boost::ends_with(params.at(0), L"_ALPHA"))
78         {
79                 return core::frame_producer::empty();
80         }
81
82         auto& url = params.at(0);
83         auto channel_layer_spec = url.substr(PREFIX.length());
84         auto dash = channel_layer_spec.find(L"-");
85         bool has_layer_spec = dash != std::wstring::npos;
86         int channel_id;
87
88         if (has_layer_spec)
89                 channel_id = boost::lexical_cast<int>(channel_layer_spec.substr(0, dash));
90         else
91                 channel_id = boost::lexical_cast<int>(channel_layer_spec);
92
93         auto found_channel = boost::find_if(dependencies.channels, [=](spl::shared_ptr<core::video_channel> ch) { return ch->index() == channel_id; });
94
95         if (found_channel == dependencies.channels.end())
96                 CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"No channel with id " + boost::lexical_cast<std::wstring>(channel_id)));
97
98         auto params2 = params;
99         params2.erase(params2.begin());
100
101         auto frames_delay                       = get_param(L"FRAMES_DELAY", params2, 0);
102         bool no_auto_deinterlace        = contains_param(L"NO_AUTO_DEINTERLACE", params2);
103
104         if (has_layer_spec)
105         {
106                 auto layer = boost::lexical_cast<int>(channel_layer_spec.substr(dash + 1));
107
108                 return create_layer_producer(*found_channel, layer, frames_delay, dependencies.format_desc);
109         }
110         else
111         {
112                 return create_channel_producer(dependencies, *found_channel, frames_delay, no_auto_deinterlace);
113         }
114 }
115
116 }}