UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
available_settings.cpp
Go to the documentation of this file.
1#include <QString>
2#include <QJsonDocument>
3#include <QJsonObject>
4#include <QJsonArray>
5#include <QMessageBox>
6#include <cstring>
9
10#include <iostream>
11#include <map>
12#include <algorithm>
13
14static bool vectorContains(const std::vector<std::string> &v, const std::string & s){
15 for(unsigned i = 0; i < v.size(); i++){
16 if(v[i] == s)
17 return true;
18 }
19 return false;
20}
21
23#define X(type, str) case type: return str;
24 switch(type){
26 case SETTING_TYPE_COUNT: return "";
27 }
28#undef X
29
30 abort(); //Should be unreachable
31}
32
33SettingType strToSettingType(std::string_view sv){
34#define X(type, str) if(sv == str) return type; else
36 return SETTING_TYPE_UNKNOWN;
37 }
38#undef X
39
40 abort(); //Should be unreachable
41}
42
43void AvailableSettings::queryProcessLine(std::string_view line){
44 constexpr std::string_view module_cap_prefix = "[cap][";
45 if(sv_is_prefix(line, module_cap_prefix)){
46 line.remove_prefix(module_cap_prefix.size());
47 if(line.empty())
48 return;
49
50 auto module_type = tokenize(line, ']');
51 auto module_name = sv_trim_whitespace(tokenize(line, ']'));
52
53 if(!module_type.empty() && !module_name.empty())
54 available[strToSettingType(module_type)].emplace_back(module_name);
55
56 return;
57 }
58
59 constexpr std::string_view devStr = "[capability][device]";
60 constexpr std::string_view codecStr = "[capability][video_compress]";
61 constexpr std::string_view endMarkerStr = "[capability][end]";
62
63 if(sv_is_prefix(line, devStr)){
64 line.remove_prefix(devStr.size());
65 queryDevice(line);
66 } else if(sv_is_prefix(line, codecStr)){
67 line.remove_prefix(codecStr.size());
69 } else if(sv_is_prefix(line, endMarkerStr)){
70 endMarkerFound = true;
71 }
72}
73
74void AvailableSettings::parseStateVersion(std::string_view line){
75 int ver = 0;
76 std::string_view verStr = "[capability][start] version ";
77
78 if(sv_is_prefix(line, verStr)){
79 line.remove_prefix(verStr.size());
80 parse_num(line, ver);
81
82 const int expectedVersion = 4;
83 if(ver != expectedVersion){
84 QMessageBox msgBox;
85 QString msg = "Capabilities start marker with expected version not found"
86 " in ug output.";
87 if(ver != 0)
88 msg += " Version found: " + QString::number(ver);
89 msgBox.setText(msg);
90 msgBox.setIcon(QMessageBox::Critical);
91 msgBox.exec();
92 parseFunc = nullptr;
93 } else {
95 }
96 }
97}
98
103
105 for(auto& i : available){
106 i.clear();
107 }
108 for(auto& i : devices){
109 i.clear();
110 }
111 videoCompressModules.clear();
112 videoCompressCodecs.clear();
113 videoCompressModules.emplace_back(CompressModule{"", {}, });
114 videoCompressCodecs.emplace_back(Codec{"None", "", {Encoder{"default", ""}}, 0});
115
117}
118
120 std::sort(videoCompressCodecs.begin(), videoCompressCodecs.end(),
121 [](const Codec& a, const Codec& b){
122 return a.priority < b.priority;
123 });
124}
125
126void AvailableSettings::queryLine(std::string_view line){
127 if(!parseFunc || (!sv_is_prefix(line, "[cap]") && !sv_is_prefix(line, "[capability]")))
128 return;
129
130 (this->*parseFunc)(line);
131}
132
133static void maybeWriteString (const QJsonObject& obj,
134 const char *key,
135 std::string& result)
136{
137 if(obj.contains(key) && obj[key].isString()){
138 result = obj[key].toString().toStdString();
139 }
140}
141
142std::vector<CapabOpt> parseCapabOpts(const QJsonObject& obj){
143 std::vector<CapabOpt> opts;
144
145 if(obj.contains("options") && obj["options"].isArray()){
146 for(const QJsonValue &val : obj["options"].toArray()){
147 QJsonObject optJson = val.toObject();
148
149 CapabOpt capabOpt;
150 maybeWriteString(optJson, "display_name", capabOpt.displayName);
151 maybeWriteString(optJson, "display_desc", capabOpt.displayDesc);
152 maybeWriteString(optJson, "placeholder_text", capabOpt.placeholder);
153 maybeWriteString(optJson, "key", capabOpt.key);
154 maybeWriteString(optJson, "opt_str", capabOpt.optStr);
155 if(optJson.contains("is_boolean") && optJson["is_boolean"].isString()){
156 capabOpt.booleanOpt = optJson["is_boolean"].toString() == "t";
157 }
158
159 opts.emplace_back(std::move(capabOpt));
160 }
161 }
162
163 return opts;
164}
165
166void AvailableSettings::queryVideoCompress(std::string_view line){
167 QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromRawData(line.data(), line.size()));
168 if(!doc.isObject())
169 return;
170
171 CompressModule compMod;
172 QJsonObject obj = doc.object();
173 maybeWriteString(obj, "name", compMod.name);
174
175
176 compMod.opts = parseCapabOpts(obj);
177
178 if(obj.contains("codecs") && obj["codecs"].isArray()){
179 for(const QJsonValue &val : obj["codecs"].toArray()){
180 QJsonObject codecJson = val.toObject();
181
182 Codec codec;
183 maybeWriteString(codecJson, "name", codec.name);
184 codec.module_name = compMod.name;
185 if(codecJson.contains("priority") && codecJson["priority"].isDouble()){
186 codec.priority = codecJson["priority"].toInt();
187 }
188
189 if(codecJson.contains("encoders") && codecJson["encoders"].isArray()){
190 for(const QJsonValue &val : codecJson["encoders"].toArray()){
191 QJsonObject encoderJson = val.toObject();
192
194 maybeWriteString(encoderJson, "name", encoder.name);
195 maybeWriteString(encoderJson, "opt_str", encoder.optStr);
196
197 codec.encoders.emplace_back(std::move(encoder));
198 }
199 }
200
201 if(codec.encoders.empty()){
202 codec.encoders.emplace_back(Encoder{"default", ""});
203 }
204
205 videoCompressCodecs.emplace_back(std::move(codec));
206 }
207 }
208
209 videoCompressModules.emplace_back(std::move(compMod));
210}
211
212void AvailableSettings::queryDevice(std::string_view line){
213 static std::map<std::string, SettingType> settingTypeMap = {
214 {"video_cap", VIDEO_SRC},
215 {"video_disp", VIDEO_DISPLAY},
216 {"audio_play", AUDIO_PLAYBACK},
217 {"audio_cap", AUDIO_SRC},
218 };
219
220 QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromRawData(line.data(), line.size()));
221 if(!doc.isObject())
222 return;
223
224 Device dev;
225 QJsonObject obj = doc.object();
226 maybeWriteString(obj, "name", dev.name);
227 maybeWriteString(obj, "module", dev.type);
228 maybeWriteString(obj, "device", dev.deviceOpt);
229
230 if(obj.contains("extra") && obj["extra"].isObject()){
231 const auto& extraObj = obj["extra"].toObject();
232 for(auto it = extraObj.constBegin(); it != extraObj.constEnd(); it++){
233 if(it.value().isString()){
234 dev.extra[it.key().toStdString()] = it.value().toString().toStdString();
235 }
236 }
237 }
238
239 if(obj.contains("modes") && obj["modes"].isArray()){
240 for(const QJsonValue &val : obj["modes"].toArray()){
241 if(val.isObject()){
242 QJsonObject modeJson = val.toObject();
243
245
246 maybeWriteString(modeJson, "name", mode.name);
247
248 if(modeJson.contains("opts") && modeJson["opts"].isObject()){
249 QJsonObject modeOpts = modeJson["opts"].toObject();
250 for(const QString &key : modeOpts.keys()){
251 if(modeOpts[key].isString()){
252 mode.opts.push_back(SettingVal{key.toStdString(),
253 modeOpts[key].toString().toStdString()});
254 }
255 }
256 dev.modes.push_back(std::move(mode));
257 }
258 }
259 }
260 }
261
262 dev.opts = parseCapabOpts(obj);
263
264 SettingType settingType = SETTING_TYPE_UNKNOWN;
265 if(obj.contains("purpose") && obj["purpose"].isString()){
266 settingType = settingTypeMap[obj["purpose"].toString().toStdString()];
267 }
268 dev.settingType = settingType;
269 devices[settingType].push_back(std::move(dev));
270}
271
272bool AvailableSettings::isAvailable(const std::string &name, SettingType type) const{
274}
275
276const std::vector<std::string>& AvailableSettings::getAvailableSettings(SettingType type) const{
277 return available[type];
278}
279
280const std::vector<Device>& AvailableSettings::getDevices(SettingType type) const{
281 return devices[type];
282}
283
int void * val
static bool vectorContains(const std::vector< std::string > &v, const std::string &s)
const char * settingTypeToStr(SettingType type)
SettingType strToSettingType(std::string_view sv)
static void maybeWriteString(const QJsonObject &obj, const char *key, std::string &result)
std::vector< CapabOpt > parseCapabOpts(const QJsonObject &obj)
#define SETTING_TYPE_LIST
SettingType strToSettingType(std::string_view sv)
@ SETTING_TYPE_COUNT
void parseStateVersion(std::string_view line)
void queryLine(std::string_view line)
void queryVideoCompress(std::string_view line)
std::vector< CompressModule > videoCompressModules
bool isAvailable(const std::string &name, SettingType type) const
std::vector< Codec > videoCompressCodecs
std::vector< std::string > available[SETTING_TYPE_COUNT]
const std::vector< Device > & getDevices(SettingType type) const
std::vector< Device > devices[SETTING_TYPE_COUNT]
const std::vector< std::string > & getAvailableSettings(SettingType type) const
void(AvailableSettings::* parseFunc)(std::string_view str)
void queryDevice(std::string_view line)
void queryProcessLine(std::string_view line)
const char * doc
Definition host.cpp:923
enum openssl_mode mode
Option::OptType type
Definition settings.cpp:194
const char * name
Definition settings.cpp:193
std::string_view tokenize(std::string_view &str, char delim, char quot)
Tokenizer for string_view.
std::string_view sv_trim_whitespace(std::string_view sv)
bool parse_num(std::string_view sv, T &res, int base=10)
bool sv_is_prefix(std::string_view haystack, std::string_view needle)
std::string optStr
std::string displayName
std::string displayDesc
std::string key
std::string placeholder
std::vector< CapabOpt > opts
std::string type
std::map< std::string, std::string > extra
std::vector< CapabOpt > opts
SettingType settingType
std::vector< DeviceMode > modes
std::string name
std::string deviceOpt
std::string name
std::vector< encoder > encoders
std::string name
const char * key
Definition cineform.cpp:125