1 /*
2 * H.265 video codec.
3 * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4 *
5 * Authors: struktur AG, Dirk Farin <farin@struktur.de>
6 *
7 * This file is part of libde265.
8 *
9 * libde265 is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of
12 * the License, or (at your option) any later version.
13 *
14 * libde265 is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with libde265. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "configparam.h"
24
25 #include <string.h>
26 #include <ctype.h>
27 #include <sstream>
28 #include <iomanip>
29 #include <iostream>
30 #include <algorithm>
31 #include <typeinfo>
32
33 #ifndef RTTI_ENABLED
34 #error "Need to compile with RTTI enabled."
35 #endif
36
remove_option(int * argc,char ** argv,int idx,int n=1)37 static void remove_option(int* argc,char** argv,int idx, int n=1)
38 {
39 for (int i=idx+n;i<*argc;i++) {
40 argv[i-n] = argv[i];
41 }
42
43 *argc-=n;
44 }
45
46
processCmdLineArguments(char ** argv,int * argc,int idx)47 bool option_string::processCmdLineArguments(char** argv, int* argc, int idx)
48 {
49 if (argv==NULL) { return false; }
50 if (idx >= *argc) { return false; }
51
52 value = argv[idx];
53 value_set = true;
54
55 remove_option(argc,argv,idx,1);
56
57 return true;
58 }
59
60
set_range(int mini,int maxi)61 void option_int::set_range(int mini,int maxi)
62 {
63 have_low_limit =true;
64 have_high_limit=true;
65 low_limit =mini;
66 high_limit=maxi;
67 }
68
getTypeDescr() const69 std::string option_int::getTypeDescr() const
70 {
71 std::stringstream sstr;
72 sstr << "(int)";
73
74 if (have_low_limit || have_high_limit) { sstr << " "; }
75 if (have_low_limit) { sstr << low_limit << " <= "; }
76 if (have_low_limit || have_high_limit) { sstr << "x"; }
77 if (have_high_limit) { sstr << " <= " << high_limit; }
78
79 if (!valid_values_set.empty()) {
80 sstr << " {";
81 bool first=true;
82 FOR_LOOP(int, v, valid_values_set) {
83 if (!first) sstr << ","; else first=false;
84 sstr << v;
85 }
86 sstr << "}";
87 }
88
89 return sstr.str();
90 }
91
processCmdLineArguments(char ** argv,int * argc,int idx)92 bool option_int::processCmdLineArguments(char** argv, int* argc, int idx)
93 {
94 if (argv==NULL) { return false; }
95 if (idx >= *argc) { return false; }
96
97 int v = atoi(argv[idx]);
98 if (!is_valid(v)) { return false; }
99
100 value = v;
101 value_set = true;
102
103 remove_option(argc,argv,idx,1);
104
105 return true;
106 }
107
is_valid(int v) const108 bool option_int::is_valid(int v) const
109 {
110 if (have_low_limit && v<low_limit) { return false; }
111 if (have_high_limit && v>high_limit) { return false; }
112
113 if (!valid_values_set.empty()) {
114 auto iter = std::find(valid_values_set.begin(), valid_values_set.end(), v);
115 if (iter==valid_values_set.end()) { return false; }
116 }
117
118 return true;
119 }
120
get_default_string() const121 std::string option_int::get_default_string() const
122 {
123 std::stringstream sstr;
124 sstr << default_value;
125 return sstr.str();
126 }
127
128
getTypeDescr() const129 std::string choice_option_base::getTypeDescr() const
130 {
131 std::vector<std::string> choices = get_choice_names();
132
133 std::stringstream sstr;
134 sstr << "{";
135
136 bool first=true;
137 #ifdef FOR_LOOP_AUTO_SUPPORT
138 FOR_LOOP(auto, c, choices) {
139 #else
140 FOR_LOOP(std::string, c, choices) {
141 #endif
142 if (first) { first=false; }
143 else { sstr << ","; }
144
145 sstr << c;
146 }
147
148 sstr << "}";
149 return sstr.str();
150 }
151
152
153 bool choice_option_base::processCmdLineArguments(char** argv, int* argc, int idx)
154 {
155 if (argv==NULL) { return false; }
156 if (idx >= *argc) { return false; }
157
158 std::string value = argv[idx];
159
160 std::cout << "set " << value << "\n";
161 bool success = set_value(value);
162 std::cout << "success " << success << "\n";
163
164 remove_option(argc,argv,idx,1);
165
166 return success;
167 }
168
169
170 static char* fill_strings_into_memory(const std::vector<std::string>& strings_list)
171 {
172 // calculate memory requirement
173
174 int totalStringLengths = 0;
175 #ifdef FOR_LOOP_AUTO_SUPPORT
176 FOR_LOOP(auto, str, strings_list) {
177 #else
178 FOR_LOOP(std::string, str, strings_list) {
179 #endif
180 totalStringLengths += str.length() +1; // +1 for null termination
181 }
182
183 int numStrings = strings_list.size();
184
185 int pointersSize = (numStrings+1) * sizeof(const char*);
186
187 char* memory = new char[pointersSize + totalStringLengths];
188
189
190 // copy strings to memory area
191
192 char* stringPtr = memory + (numStrings+1) * sizeof(const char*);
193 const char** tablePtr = (const char**)memory;
194
195 #ifdef FOR_LOOP_AUTO_SUPPORT
196 FOR_LOOP(auto, str, strings_list) {
197 #else
198 FOR_LOOP(std::string, str, strings_list) {
199 #endif
200 *tablePtr++ = stringPtr;
201
202 strcpy(stringPtr, str.c_str());
203 stringPtr += str.length()+1;
204 }
205
206 *tablePtr = NULL;
207
208 return memory;
209 }
210
211
212 const char** choice_option_base::get_choices_string_table() const
213 {
214 if (choice_string_table==NULL) {
215 choice_string_table = fill_strings_into_memory(get_choice_names());
216 }
217
218 return (const char**)choice_string_table;
219 }
220
221
222
223 bool config_parameters::parse_command_line_params(int* argc, char** argv, int* first_idx_ptr,
224 bool ignore_unknown_options)
225 {
226 int first_idx=1;
227 if (first_idx_ptr) { first_idx = *first_idx_ptr; }
228
229 for (int i=first_idx;i < *argc;i++) {
230
231 if (argv[i][0]=='-') {
232 // option
233
234 if (argv[i][1]=='-') {
235 // long option
236
237 bool option_found=false;
238
239 for (int o=0;o<mOptions.size();o++) {
240 if (mOptions[o]->hasLongOption() && strcmp(mOptions[o]->getLongOption().c_str(),
241 argv[i]+2)==0) {
242 option_found=true;
243
244 bool success = mOptions[o]->processCmdLineArguments(argv,argc, i+1);
245 if (!success) {
246 if (first_idx_ptr) { *first_idx_ptr = i; }
247 return false;
248 }
249
250 remove_option(argc,argv,i);
251 i--;
252
253 break;
254 }
255 }
256
257 if (option_found == false && !ignore_unknown_options) {
258 return false;
259 }
260 }
261 else {
262 // short option
263
264 bool is_single_option = (argv[i][1] != 0 && argv[i][2]==0);
265 bool do_remove_option = true;
266
267 for (int n=1; argv[i][n]; n++) {
268 char option = argv[i][n];
269
270 bool option_found=false;
271
272 for (int o=0;o<mOptions.size();o++) {
273 if (mOptions[o]->getShortOption() == option) {
274 option_found=true;
275
276 bool success;
277 if (is_single_option) {
278 success = mOptions[o]->processCmdLineArguments(argv,argc, i+1);
279 }
280 else {
281 success = mOptions[o]->processCmdLineArguments(NULL,NULL, 0);
282 }
283
284 if (!success) {
285 if (first_idx_ptr) { *first_idx_ptr = i; }
286 return false;
287 }
288
289 break;
290 }
291 }
292
293 if (!option_found) {
294 if (!ignore_unknown_options) {
295 fprintf(stderr, "unknown option -%c\n",option);
296 return false;
297 }
298 else {
299 do_remove_option=false;
300 }
301 }
302
303 } // all short options
304
305 if (do_remove_option) {
306 remove_option(argc,argv,i);
307 i--;
308 }
309 } // is short option
310 } // is option
311 } // all command line arguments
312
313 return true;
314 }
315
316
317 void config_parameters::print_params() const
318 {
319 for (int i=0;i<mOptions.size();i++) {
320 const option_base* o = mOptions[i];
321
322 std::stringstream sstr;
323 sstr << " ";
324 if (o->hasShortOption()) {
325 sstr << '-' << o->getShortOption();
326 } else {
327 sstr << " ";
328 }
329
330 if (o->hasShortOption() && o->hasLongOption()) {
331 sstr << ", ";
332 } else {
333 sstr << " ";
334 }
335
336 if (o->hasLongOption()) {
337 sstr << "--" << std::setw(12) << std::left << o->getLongOption();
338 } else {
339 sstr << " ";
340 }
341
342 sstr << " ";
343 sstr << o->getTypeDescr();
344
345 if (o->has_default()) {
346 sstr << ", default=" << o->get_default_string();
347 }
348
349 sstr << "\n";
350
351 std::cerr << sstr.str();
352 }
353 }
354
355
356 void config_parameters::add_option(option_base* o)
357 {
358 mOptions.push_back(o);
359 delete[] param_string_table; // delete old table, since we got a new parameter
360 param_string_table = NULL;
361 }
362
363
364 std::vector<std::string> config_parameters::get_parameter_IDs() const
365 {
366 std::vector<std::string> ids;
367
368 #ifdef FOR_LOOP_AUTO_SUPPORT
369 FOR_LOOP(auto, option, mOptions) {
370 #else
371 FOR_LOOP(option_base*, option, mOptions) {
372 #endif
373 ids.push_back(option->get_name());
374 }
375
376 return ids;
377 }
378
379
380 enum en265_parameter_type config_parameters::get_parameter_type(const char* param) const
381 {
382 option_base* option = find_option(param);
383 assert(option);
384
385 if (dynamic_cast<option_int*> (option)) { return en265_parameter_int; }
386 if (dynamic_cast<option_bool*> (option)) { return en265_parameter_bool; }
387 if (dynamic_cast<option_string*>(option)) { return en265_parameter_string; }
388 if (dynamic_cast<choice_option_base*>(option)) { return en265_parameter_choice; }
389
390 assert(false);
391 return en265_parameter_bool;
392 }
393
394
395 std::vector<std::string> config_parameters::get_parameter_choices(const char* param) const
396 {
397 option_base* option = find_option(param);
398 assert(option);
399
400 choice_option_base* o = dynamic_cast<choice_option_base*>(option);
401 assert(o);
402
403 return o->get_choice_names();
404 }
405
406
407 option_base* config_parameters::find_option(const char* param) const
408 {
409 #ifdef FOR_LOOP_AUTO_SUPPORT
410 FOR_LOOP(auto, o, mOptions) {
411 #else
412 FOR_LOOP(option_base*, o, mOptions) {
413 #endif
414 if (strcmp(o->get_name().c_str(), param)==0) { return o; }
415 }
416
417 return NULL;
418 }
419
420
421 bool config_parameters::set_bool(const char* param, bool value)
422 {
423 option_base* option = find_option(param);
424 assert(option);
425
426 option_bool* o = dynamic_cast<option_bool*>(option);
427 assert(o);
428
429 return o->set(value);
430 }
431
432 bool config_parameters::set_int(const char* param, int value)
433 {
434 option_base* option = find_option(param);
435 assert(option);
436
437 option_int* o = dynamic_cast<option_int*>(option);
438 assert(o);
439
440 return o->set(value);
441 }
442
443 bool config_parameters::set_string(const char* param, const char* value)
444 {
445 option_base* option = find_option(param);
446 assert(option);
447
448 option_string* o = dynamic_cast<option_string*>(option);
449 assert(o);
450
451 return o->set(value);
452 }
453
454 bool config_parameters::set_choice(const char* param, const char* value)
455 {
456 option_base* option = find_option(param);
457 assert(option);
458
459 choice_option_base* o = dynamic_cast<choice_option_base*>(option);
460 assert(o);
461
462 return o->set(value);
463 }
464
465
466
467 const char** config_parameters::get_parameter_choices_table(const char* param) const
468 {
469 option_base* option = find_option(param);
470 assert(option);
471
472 choice_option_base* o = dynamic_cast<choice_option_base*>(option);
473 assert(o);
474
475 return o->get_choices_string_table();
476 }
477
478 const char** config_parameters::get_parameter_string_table() const
479 {
480 if (param_string_table==NULL) {
481 param_string_table = fill_strings_into_memory(get_parameter_IDs());
482 }
483
484 return (const char**)param_string_table;
485 }
486