UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
settings.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <algorithm>
3#include <random>
4#include "settings.hpp"
6
7Option::Callback::Callback(fcn_type func_ptr, void *opaque) :
8 func_ptr(func_ptr),
9 opaque(opaque)
10{
11
12}
13
14void Option::Callback::operator()(Option& opt, bool suboption) const{
15 func_ptr(opt, suboption, opaque);
16}
17
19 return func_ptr == o.func_ptr && opaque == o.opaque;
20}
21
22std::string Option::getName() const{
23 return name;
24}
25
26std::string Option::getValue() const{
27 return value;
28}
29
30std::string Option::getParam() const{
31 return param;
32}
33
34std::string Option::getSubVals() const{
35 std::string out;
36
37 for(const auto &sub : suboptions){
38 if(sub.first.empty() || sub.first == value){
39 out += sub.second->getLaunchOption();
40 }
41 }
42
43 return out;
44}
45
46std::string Option::getLaunchOption() const{
48 return enabled ? param : "";
49 }
50
51 std::string out = "";
52 if(enabled && !value.empty() && type != OptType::SilentOpt)
53 out = param + value;
54
55 out += getSubVals();
56
57 return out;
58}
59
61 for(const auto &callback : onChangeCallbacks){
62 callback(*this, false);
63 }
64}
65
66void Option::suboptionChanged(Option &opt, bool, void *opaque){
67 Option *obj = static_cast<Option *>(opaque);
68 for(const auto &callback : obj->onChangeCallbacks){
69 callback(opt, true);
70 }
71}
72
73void Option::setValue(const std::string &val, bool suppressCallback){
74 value = val;
75
77 enabled = val == "t";
78 } else {
79 enabled = !val.empty();
80 }
81
82 if(!suppressCallback)
83 changed();
84}
85
86void Option::setDefaultValue(const std::string &val){
88}
89
90void Option::setEnabled(bool enable, bool suppressCallback){
91 enabled = enable;
92 if(!suppressCallback)
93 changed();
94}
95
96void Option::addSuboption(Option *sub, const std::string &limit){
97 auto pair = std::make_pair(limit, sub);
98 auto it = std::find(suboptions.begin(), suboptions.end(), pair);
99
100 if(it != suboptions.end())
101 return;
102
104 suboptions.push_back(pair);
105}
106
110
112 auto it = std::find(onChangeCallbacks.begin(), onChangeCallbacks.end(), callback);
113
114 if(it == onChangeCallbacks.end()){
115 std::cout << "Attempted to remove non-existent callback "
116 << name
117 << std::endl;
118 return;
119 }
120
121#ifdef DEBUG
122 std::cout << "Removing callback "
123 << name
124 << std::endl;
125#endif
126 onChangeCallbacks.erase(it);
127}
128
132
133#ifdef DEBUG
134static void test_callback(Option &opt, bool, void *){
135 std::cout << "Callback: " << opt.getName()
136 << ": " << opt.getValue()
137 << " (" << opt.isEnabled() << ")" << std::endl;
138}
139#endif
140
141static void fec_builder_callback(Option &opt, bool subopt, void *){
142 if(!subopt)
143 return;
144
146 Option &fecOpt = settings->getOption("network.fec");
147 bool enabled = settings->getOption("network.fec.enabled").isEnabled();
148
149 std::string type = settings->getOption("network.fec.type").getValue();
150
151 if(type.empty() || !enabled){
152 fecOpt.setValue("");
153 } else if(type == "mult"){
154 fecOpt.setValue("mult:" + settings->getOption("network.fec.mult.factor").getValue());
155 } else if(type == "rs"){
156 fecOpt.setValue("rs:"
157 + settings->getOption("network.fec.rs.k").getValue()
158 + ":" + settings->getOption("network.fec.rs.n").getValue());
159 } else if(type == "ldgm"){
160 fecOpt.setValue("ldgm:"
161 + settings->getOption("network.fec.ldgm.k").getValue()
162 + ":" + settings->getOption("network.fec.ldgm.m").getValue()
163 + ":" + settings->getOption("network.fec.ldgm.c").getValue()
164 + settings->getOption("network.fec.ldgm.device").getParam()
165 + settings->getOption("network.fec.ldgm.device").getValue());
166 }
167
168
169}
170
171static void fec_auto_callback(Option &opt, bool /*subopt*/, void *){
173
174 if(!settings->getOption("network.fec.auto").isEnabled())
175 return;
176
177 Option &fecOpt = settings->getOption("network.fec.type");
178 const std::string &video_compress = settings->getOption("video.compress").getValue();
179
180 if(video_compress == ""){
181 fecOpt.setValue("");
182 } else if(video_compress == "jpeg"){
183 fecOpt.setValue("ldgm");
184 } else if(video_compress == "libavcodec"
185 && settings->getOption("video.compress.libavcodec.codec").getValue() == "MJPEG"){
186 fecOpt.setValue("ldgm");
187 } else {
188 fecOpt.setValue("rs");
189 }
190}
191
192const static struct{
193 const char *name;
195 const char *param;
196 const char *defaultVal;
198 const char *parent;
199 const char *limit;
200} optionList[] = {
201 {"extraOpts", Option::StringOpt, "", "", false, "", ""},
202 {"video.source", Option::StringOpt, " -t ", "", false, "", ""},
203 {"video.source.embeddedAudioAvailable", Option::SilentOpt, "", "", false, "", ""},
204 {"testcard.width", Option::StringOpt, ":", "", false, "video.source", "testcard"},
205 {"testcard.height", Option::StringOpt, ":", "", false, "video.source", "testcard"},
206 {"testcard.fps", Option::StringOpt, ":", "", false, "video.source", "testcard"},
207 {"testcard.format", Option::StringOpt, ":", "", false, "video.source", "testcard"},
208 {"screen.fps", Option::StringOpt, ":fps=", "", false, "video.source", "screen"},
209 {"v4l2.codec", Option::StringOpt, ":codec=", "", false, "video.source", "v4l2"},
210 {"v4l2.size", Option::StringOpt, ":size=", "", false, "video.source", "v4l2"},
211 {"v4l2.tpf", Option::StringOpt, ":tpf=", "", false, "video.source", "v4l2"},
212 {"v4l2.force_rgb", Option::BoolOpt, ":convert=RGB", "t", true, "video.source", "v4l2"},
213 {"dshow.mode", Option::StringOpt, ":mode=", "", false, "video.source", "dshow"},
214 {"dshow.force_rgb", Option::BoolOpt, ":RGB", "t", true, "video.source", "dshow"},
215 {"avfoundation.mode", Option::StringOpt, ":mode=", "", false, "video.source", "avfoundation"},
216 {"avfoundation.fps", Option::StringOpt, ":fps=", "", false, "video.source", "avfoundation"},
217 {"decklink.modeOpt", Option::StringOpt, ":", "", false, "video.source", "decklink"},
218 {"video.display", Option::StringOpt, " -d ", "", false, "", ""},
219 {"video.display.embeddedAudioAvailable", Option::SilentOpt, "", "", false, "", ""},
220 {"video.compress", Option::StringOpt, " -c ", "", false, "", ""},
221 {"audio.source", Option::StringOpt, " -s ", "", false, "", ""},
222 {"audio.source.channels", Option::StringOpt, " --audio-capture-format channels=", "", false, "", ""},
223 {"audio.playback", Option::StringOpt, " -r ", "", false, "", ""},
224 {"audio.compress", Option::StringOpt, " --audio-codec ", "", false, "", ""},
225 {"bitrate", Option::StringOpt, ":bitrate=", "", false, "audio.compress", ""},
226 {"network.destination", Option::StringOpt, " ", "", false, "", ""},
227 {"network.port", Option::StringOpt, " -P ", "5004", false, "", ""},
228 {"network.control_port", Option::StringOpt, " --control-port ", "8888", true, "", ""},
229 {"network.control_port.random", Option::BoolOpt, "", "", true, "", ""},
230 {"network.fec", Option::StringOpt, " -f ", "", false, "", ""},
231 {"type", Option::SilentOpt, "", "", false, "network.fec", ""},
232 {"enabled", Option::BoolOpt, "", "f", false, "network.fec", ""},
233 {"mult.factor", Option::SilentOpt, ":", "2", false, "network.fec", ""},
234 {"ldgm.k", Option::SilentOpt, ":", "256", false, "network.fec", ""},
235 {"ldgm.m", Option::SilentOpt, ":", "192", false, "network.fec", ""},
236 {"ldgm.c", Option::SilentOpt, ":", "5", false, "network.fec", ""},
237 {"ldgm.device", Option::SilentOpt, " --param ldgm-device=", "CPU", false, "network.fec", ""},
238 {"rs.k", Option::SilentOpt, ":", "200", false, "network.fec", ""},
239 {"rs.n", Option::SilentOpt, "", "220", false, "network.fec", ""},
240 {"network.fec.auto", Option::BoolOpt, "", "t", true, "", ""},
241 {"decode.hwaccel", Option::BoolOpt, " --param use-hw-accel", "f", false, "", ""},
242 {"advanced", Option::BoolOpt, "", "f", false, "", ""},
243 {"preview", Option::BoolOpt, "", "t", true, "", ""},
244 {"vuMeter", Option::BoolOpt, "", "t", true, "", ""},
245 {"errors_fatal", Option::BoolOpt, " --param errors-fatal", "t", true, "", ""},
246 {"encryption", Option::StringOpt, " --encryption ", "", false, "", ""},
248
249const struct {
250 const char *name;
252} optionCallbacks[] = {
253 {"network.fec", fec_builder_callback},
254 {"video.compress", fec_auto_callback},
255 {"network.fec.auto", fec_auto_callback},
257
258Settings::Settings() : dummy(this){
259 std::random_device rd;
260 std::mt19937 gen(rd());
261 std::uniform_int_distribution<> bounds(0, ('9' - '0') + ('z' - 'a'));
262 for(int i = 0; i < 8; i++){
263 int rand = bounds(gen);
264 if(rand <= 9)
265 sessRndKey += '0' + rand;
266 else
267 sessRndKey += 'a' + (rand - 9);
268 }
269
270 for(const auto &i : optionList){
271 auto &opt = addOption(i.name,
272 i.type,
273 i.param,
274 i.defaultVal,
275 i.enabled,
276 i.parent,
277 i.limit);
278#ifdef DEBUG
279 if(!i.parent[0])
280 opt.addOnChangeCallback(Option::Callback(test_callback, nullptr));
281#endif
282 (void) opt; //suppress unused warning
283 }
284
285 for(const auto &i : optionCallbacks){
286 getOption(i.name).addOnChangeCallback(Option::Callback(i.callback, nullptr));
287 }
288
289 std::cout << getLaunchParams() << std::endl;
290}
291
292std::string Settings::getControlPort() const{
293 if(getOption("network.control_port.random").isEnabled())
294 return "0";
295
296 return getOption("network.control_port").getValue();
297}
298
299std::string Settings::getLaunchParams() const{
300 std::string out;
301
302 out += getOption("extraOpts").getLaunchOption();
303
304 if(getOption("preview").isEnabled()){
305 out += " --capture-filter preview";
306 out += ":key=" + getSessRndKey();
307 }
308
309 out += getOption("video.source").getLaunchOption();
310 out += getOption("video.compress").getLaunchOption();
311 const auto &dispOpt = getOption("video.display");
312 if(dispOpt.isEnabled()){
313 if(getOption("preview").isEnabled()){
314 out += dispOpt.getParam();
315 out += "multiplier:" + dispOpt.getValue() + dispOpt.getSubVals();
316 out += "#preview";
317 out += ":key=" + getSessRndKey();
318 } else {
319 out += getOption("video.display").getLaunchOption();
320 }
321 } else {
322 if(getOption("preview").isEnabled()){
323 out += dispOpt.getParam();
324 out += "preview";
325 out += ":key=" + getSessRndKey();
326 }
327 }
328
329 out += " --audio-filter controlport_stats";
330 out += getOption("audio.source").getLaunchOption();
331 out += getOption("audio.source.channels").getLaunchOption();
332 out += getOption("audio.compress").getLaunchOption();
333 std::string audioPlay = getOption("audio.playback").getLaunchOption();
334 if(audioPlay.empty() && getOption("preview").isEnabled()){
335 audioPlay = " -r dummy";
336 }
337 out += audioPlay;
338 out += getOption("network.fec").getLaunchOption();
339 out += getOption("encryption").getLaunchOption();
340 out += getOption("network.port").getLaunchOption();
341 out += getOption("network.control_port").getParam();
342 out += getControlPort();
343 out += getOption("network.destination").getLaunchOption();
344 out += getOption("decode.hwaccel").getLaunchOption();
345 out += getOption("errors_fatal").getLaunchOption();
346 return out;
347}
348
349std::string Settings::getPreviewParams() const{
350 std::string out;
351
352 out += getOption("extraOpts").getLaunchOption();
353
354 out += " --capture-filter preview";
355 out += ":key=" + getSessRndKey();
356 out += ",every:0";
357 out += getOption("video.source").getLaunchOption();
358 out += " -d preview";
359 out += ":key=" + getSessRndKey();
360 out += " --audio-filter controlport_stats#discard";
361 out += getOption("audio.source").getLaunchOption();
362 out += getOption("audio.source.channels").getLaunchOption();
363 out += " -r dummy";
364 out += getOption("network.control_port").getParam();
365 out += getControlPort();
366 out += getOption("encryption").getLaunchOption();
367
368 return out;
369}
370
371Option& Settings::getOption(const std::string &opt){
372 auto search = options.find(opt);
373
374 if(search == options.end()){
375 std::unique_ptr<Option> newOption(new Option(this, opt));
376 auto p = newOption.get();
377 options[opt] = std::move(newOption);
378 return *p;
379 }
380
381 return *search->second;
382}
383
384const Option& Settings::getOption(const std::string &opt) const{
385 auto search = options.find(opt);
386
387 if(search == options.end())
388 return dummy;
389
390 return *search->second;
391}
392
393const std::map<std::string, std::unique_ptr<Option>>& Settings::getOptionMap() const{
394 return options;
395}
396
399 const std::string &param,
400 const std::string &value,
401 bool enabled,
402 const std::string &parent,
403 const std::string &limit)
404{
405 if(!parent.empty())
406 name = parent + "." + name;
407
408 auto search = options.find(name);
409
410 Option *opt;
411
412 if(search == options.end()){
413 std::unique_ptr<Option> newOption(new Option(this, name));
414 opt = newOption.get();
415 options[name] = std::move(newOption);
416 } else {
417 opt = search->second.get();
418 }
419
420 opt->setParam(param);
421 opt->setType(type);
422 opt->setValue(value);
423 opt->setDefaultValue(value);
424 opt->setEnabled(enabled);
425
426 if(!parent.empty()){
428 }
429
430 return *opt;
431}
432
434 return getOption("advanced").getValue() == "t";
435}
436
438 for(auto &i : options){
439 i.second->changed();
440 }
441}
442
443static void addDevOpt(Settings* settings, const Device& dev, const char *parent){
444 settings->addOption(dev.type + ".device",
446 "",
447 "",
448 false,
449 parent,
450 dev.type);
451}
452
454 struct{
456 const char *optPrefix;
457 } devTypes[] = {
458 {VIDEO_SRC, "video.source"},
459 {VIDEO_DISPLAY, "video.display"},
460 {AUDIO_SRC, "audio.source"},
461 {AUDIO_PLAYBACK, "audio.playback"},
462 };
463
464 for(const auto& devType : devTypes){
465 for(const auto& dev : availSettings->getDevices(devType.type)){
466 addDevOpt(this, dev, devType.optPrefix);
467
468 for(const auto& devOpt : dev.opts){
469 addOption(dev.deviceOpt + "." + devOpt.key,
470 devOpt.booleanOpt ? Option::BoolOpt : Option::StringOpt,
471 devOpt.optStr,
472 "",
473 false,
474 std::string(devType.optPrefix) + "." + dev.type + ".device",
475 dev.deviceOpt);
476 }
477 }
478 }
479}
480
482 for(const auto& mod : availSettings->getVideoCompressModules()){
483 addOption(mod.name + ".codec",
485 "",
486 "",
487 false,
488 "video.compress",
489 mod.name);
490
491 for(const auto& modOption: mod.opts){
492 addOption(mod.name + "." + modOption.key,
493 modOption.booleanOpt ? Option::BoolOpt : Option::StringOpt,
494 modOption.optStr,
495 "",
496 false,
497 "video.compress",
498 mod.name
499 );
500 }
501 }
502
503 for(const auto& codec : availSettings->getVideoCompressCodecs()){
504 std::string optName = "video.compress.";
505 optName += codec.module_name;
506 optName += ".codec";
507
508 addOption(codec.name + ".encoder",
510 "",
511 codec.encoders[0].optStr,
512 true,
513 optName,
514 codec.name);
515 }
516}
517
522
523
524
525/* vim: set noexpandtab: */
int void * val
const std::vector< CompressModule > & getVideoCompressModules() const
const std::vector< Codec > & getVideoCompressCodecs() const
const std::vector< Device > & getDevices(SettingType type) const
void(*)(Option &, bool, void *) fcn_type
Definition settings.hpp:16
Callback(fcn_type func_ptr, void *opaque)
Definition settings.cpp:7
bool operator==(const Callback &) const
Definition settings.cpp:18
void operator()(Option &, bool) const
Definition settings.cpp:14
fcn_type func_ptr
Definition settings.hpp:24
std::string value
Definition settings.hpp:76
void removeOnChangeCallback(const Callback &callback)
Definition settings.cpp:111
std::string getValue() const
Definition settings.cpp:26
void setType(OptType type)
Definition settings.hpp:64
void setParam(const std::string &p)
Definition settings.hpp:59
Settings * settings
Definition settings.hpp:88
Settings * getSettings()
Definition settings.cpp:129
bool enabled
Definition settings.hpp:79
void setEnabled(bool enable, bool suppressCallback=false)
Definition settings.cpp:90
std::string name
Definition settings.hpp:74
void addOnChangeCallback(Callback callback)
Definition settings.cpp:107
std::vector< Callback > onChangeCallbacks
Definition settings.hpp:85
void changed()
Definition settings.cpp:60
static void suboptionChanged(Option &opt, bool suboption, void *opaque)
Definition settings.cpp:66
OptType type
Definition settings.hpp:81
@ StringOpt
Definition settings.hpp:29
@ BoolOpt
Definition settings.hpp:30
@ SilentOpt
Definition settings.hpp:31
std::string defaultValue
Definition settings.hpp:77
void addSuboption(Option *sub, const std::string &limit="")
Definition settings.cpp:96
std::string param
Definition settings.hpp:75
std::string getSubVals() const
Definition settings.cpp:34
bool isEnabled() const
Definition settings.hpp:61
std::vector< std::pair< std::string, Option * > > suboptions
Definition settings.hpp:86
virtual void setValue(const std::string &val, bool suppressCallback=false)
Definition settings.cpp:73
std::string getName() const
Definition settings.cpp:22
virtual std::string getLaunchOption() const
Definition settings.cpp:46
std::string getParam() const
Definition settings.cpp:30
virtual void setDefaultValue(const std::string &val)
Definition settings.cpp:86
std::map< std::string, std::unique_ptr< Option > > options
Definition settings.hpp:124
const Option & getOption(const std::string &opt) const
Definition settings.cpp:384
std::string getLaunchParams() const
Definition settings.cpp:299
const std::string & getSessRndKey() const
Definition settings.hpp:117
std::string sessRndKey
Definition settings.hpp:126
std::string getPreviewParams() const
Definition settings.cpp:349
const Option dummy
Definition settings.hpp:128
void populateVideoCompressSettings(AvailableSettings *availSettings)
Definition settings.cpp:481
void populateSettingsFromCapabilities(AvailableSettings *availSettings)
Definition settings.cpp:518
const std::map< std::string, std::unique_ptr< Option > > & getOptionMap() const
Definition settings.cpp:393
std::string getControlPort() const
Definition settings.cpp:292
Option & addOption(std::string name, Option::OptType type, const std::string &param, const std::string &value="", bool enabled=true, const std::string &parent="", const std::string &limit="")
Definition settings.cpp:397
bool isAdvancedMode()
Definition settings.cpp:433
void populateDeviceSettings(AvailableSettings *availSettings)
Definition settings.cpp:453
void changedAll()
Definition settings.cpp:437
static void addDevOpt(Settings *settings, const Device &dev, const char *parent)
Definition settings.cpp:443
static const struct @0 optionList[]
const char * parent
Definition settings.cpp:198
static void fec_builder_callback(Option &opt, bool subopt, void *)
Definition settings.cpp:141
const struct @1 optionCallbacks[]
Option::OptType type
Definition settings.cpp:194
bool enabled
Definition settings.cpp:197
const char * param
Definition settings.cpp:195
const char * name
Definition settings.cpp:193
Option::Callback::fcn_type callback
Definition settings.cpp:251
const char * defaultVal
Definition settings.cpp:196
const char * limit
Definition settings.cpp:199
static void fec_auto_callback(Option &opt, bool, void *)
Definition settings.cpp:171
std::string type
std::string name
std::vector< encoder > encoders
Definition rtp.c:253