175 {
176 std::string binary =
GetFileName(std::string(argv[0]));
177 if (argc < 2) {
179 return -1;
180 }
181 const std::string command(argv[1]);
182 std::string file_path;
183 if (argc >= 3) {
184 file_path = std::string(argv[2]);
185 }
186
187 int long_index = 0;
188 const std::string short_opts = "f:c:k:o:alr:b:e:s:d:p:i:m:hCH";
189 static const struct option long_opts[] = {
190 {"files", required_argument, nullptr, 'f'},
191 {"white-channel", required_argument, nullptr, 'c'},
192 {"black-channel", required_argument, nullptr, 'k'},
193 {"output", required_argument, nullptr, 'o'},
194 {"all", no_argument, nullptr, 'a'},
195 {"loop", no_argument, nullptr, 'l'},
196 {"rate", required_argument, nullptr, 'r'},
197 {"begin", required_argument, nullptr, 'b'},
198 {"end", required_argument, nullptr, 'e'},
199 {"start", required_argument, nullptr, 's'},
200 {"delay", required_argument, nullptr, 'd'},
201 {"preload", required_argument, nullptr, 'p'},
202 {"segment-interval", required_argument, nullptr, 'i'},
203 {"segment-size", required_argument, nullptr, 'm'},
204 {"help", no_argument, nullptr, 'h'},
205 {"cpu-profile", no_argument, nullptr, 'C'},
206 {"heap-profule", no_argument, nullptr, 'H'}};
207
208 std::vector<std::string> opt_file_vec;
209 std::vector<std::string> opt_output_vec;
210 std::vector<std::string> opt_white_channels;
211 std::vector<std::string> opt_black_channels;
212 static bool enable_cpu_profile = false;
213 static bool enable_heap_profile = false;
214 bool opt_all = false;
215 bool opt_loop = false;
216 float opt_rate = 1.0f;
217 uint64_t opt_begin = 0;
218 uint64_t opt_end = std::numeric_limits<uint64_t>::max();
219 double opt_start = 0;
220 uint64_t opt_delay = 0;
221 uint32_t opt_preload = 3;
223
224 do {
225 int opt =
226 getopt_long(argc, argv, short_opts.c_str(), long_opts, &long_index);
227 if (opt == -1) {
228 break;
229 }
230 switch (opt) {
231 case 'C':
232 enable_cpu_profile = true;
233 break;
234 case 'H':
235 enable_heap_profile = true;
236 break;
237 case 'f':
239 auto opt_file_abs_path =
242 opt_file_vec.emplace_back(opt_file_abs_path);
243 } else {
244 opt_file_vec.emplace_back(std::string(optarg));
245 }
246 } else {
247 opt_file_vec.emplace_back(std::string(optarg));
248 }
249 for (int i = optind; i < argc; i++) {
250 if (*argv[i] != '-') {
253 "/" + std::string(argv[i]);
255 opt_file_vec.emplace_back(opt_file_abs_path);
256 } else {
257 opt_file_vec.emplace_back(std::string(argv[i]));
258 }
259 } else {
260 opt_file_vec.emplace_back(std::string(argv[i]));
261 }
262 } else {
263 break;
264 }
265 }
266 break;
267 case 'c':
268 opt_white_channels.emplace_back(std::string(optarg));
269 for (int i = optind; i < argc; i++) {
270 if (*argv[i] != '-') {
271 opt_white_channels.emplace_back(std::string(argv[i]));
272 } else {
273 break;
274 }
275 }
276 break;
277 case 'k':
278 opt_black_channels.emplace_back(std::string(optarg));
279 for (int i = optind; i < argc; i++) {
280 if (*argv[i] != '-') {
281 opt_black_channels.emplace_back(std::string(argv[i]));
282 } else {
283 break;
284 }
285 }
286 break;
287 case 'o':
289 auto opt_output_file_abs_path =
291 opt_output_vec.push_back(opt_output_file_abs_path);
292 } else {
293 opt_output_vec.push_back(std::string(optarg));
294 }
295 break;
296 case 'a':
297 opt_all = true;
298 break;
299 case 'l':
300 opt_loop = true;
301 break;
302 case 'r':
303 try {
304 opt_rate = std::stof(optarg);
305 } catch (const std::invalid_argument& ia) {
306 std::cout << "Invalid argument: -r/--rate " << std::string(optarg)
307 << std::endl;
308 return -1;
309 } catch (const std::out_of_range& e) {
310 std::cout << "Argument is out of range: -r/--rate "
311 << std::string(optarg) << std::endl;
312 return -1;
313 }
314 break;
315 case 'b':
316 opt_begin =
318 break;
319 case 'e':
320 opt_end =
322 break;
323 case 's':
324 try {
325 opt_start = std::stod(optarg);
326 } catch (const std::invalid_argument& ia) {
327 std::cout << "Invalid argument: -s/--start " << std::string(optarg)
328 << std::endl;
329 return -1;
330 } catch (const std::out_of_range& e) {
331 std::cout << "Argument is out of range: -s/--start "
332 << std::string(optarg) << std::endl;
333 return -1;
334 }
335 break;
336 case 'd':
337 try {
338 opt_delay = std::stoi(optarg);
339 } catch (std::invalid_argument& ia) {
340 std::cout << "Invalid argument: -d/--delay " << std::string(optarg)
341 << std::endl;
342 return -1;
343 } catch (const std::out_of_range& e) {
344 std::cout << "Argument is out of range: -d/--delay "
345 << std::string(optarg) << std::endl;
346 return -1;
347 }
348 break;
349 case 'p':
350 try {
351 opt_preload = std::stoi(optarg);
352 } catch (std::invalid_argument& ia) {
353 std::cout << "Invalid argument: -p/--preload " << std::string(optarg)
354 << std::endl;
355 return -1;
356 } catch (const std::out_of_range& e) {
357 std::cout << "Argument is out of range: -p/--preload "
358 << std::string(optarg) << std::endl;
359 return -1;
360 }
361 break;
362 case 'i':
363 try {
364 int interval_s = std::stoi(optarg);
365 if (interval_s < 0) {
366 std::cout << "Argument is less than zero: -i/--segment-interval "
367 << std::string(optarg) << std::endl;
368 return -1;
369 }
370 opt_header.set_segment_interval(interval_s * 1000000000ULL);
371 } catch (std::invalid_argument& ia) {
372 std::cout << "Invalid argument: -i/--segment-interval "
373 << std::string(optarg) << std::endl;
374 return -1;
375 } catch (const std::out_of_range& e) {
376 std::cout << "Argument is out of range: -i/--segment-interval "
377 << std::string(optarg) << std::endl;
378 return -1;
379 }
380 break;
381 case 'm':
382 try {
383 int size_mb = std::stoi(optarg);
384 if (size_mb < 0) {
385 std::cout << "Argument is less than zero: -m/--segment-size "
386 << std::string(optarg) << std::endl;
387 return -1;
388 }
389 opt_header.set_segment_raw_size(size_mb * 1024 * 1024ULL);
390 } catch (std::invalid_argument& ia) {
391 std::cout << "Invalid argument: -m/--segment-size "
392 << std::string(optarg) << std::endl;
393 return -1;
394 } catch (const std::out_of_range& e) {
395 std::cout << "Argument is out of range: -m/--segment-size "
396 << std::string(optarg) << std::endl;
397 return -1;
398 }
399 break;
400 case 'h':
402 return 0;
403 default:
404 break;
405 }
406 } while (true);
407
408
409 if (command == "info") {
410 if (file_path.empty()) {
411 std::cout << "usage: cyber_recorder info file" << std::endl;
412 return -1;
413 }
415 auto file_path_abs =
417 if (std::filesystem::exists(file_path_abs)) {
418 file_path = file_path_abs;
419 }
420 }
423 bool info_result = info.
Display(file_path);
424 return info_result ? 0 : -1;
425 } else if (command == "recover") {
426 if (opt_file_vec.empty()) {
427 std::cout << "MUST specify file option (-f)." << std::endl;
428 return -1;
429 }
430 if (opt_file_vec.size() > 1 || opt_output_vec.size() > 1) {
431 std::cout << "TOO many input/output file option (-f/-o)." << std::endl;
432 return -1;
433 }
434 if (opt_output_vec.empty()) {
435 std::string default_output_file = opt_file_vec[0] + ".recover";
436 opt_output_vec.push_back(default_output_file);
437 }
439 Recoverer recoverer(opt_file_vec[0], opt_output_vec[0]);
440 bool recover_result = recoverer.Proc();
441 return recover_result ? 0 : -1;
442 }
443
444 if (command == "play") {
445 if (opt_file_vec.empty()) {
446 std::cout << "MUST specify file option (-f)." << std::endl;
447 return -1;
448 }
459 play_param.
files_to_play.insert(opt_file_vec.begin(), opt_file_vec.end());
461 opt_black_channels.end());
463 opt_white_channels.end());
464 Player player(play_param);
465 const bool play_result = player.Init() && player.Start();
466 return play_result ? 0 : -1;
467 } else if (command == "record") {
468 if (opt_white_channels.empty() && !opt_all) {
469 std::cout
470 << "MUST specify channels option (-c) or all channels option (-a)."
471 << std::endl;
472 return -1;
473 }
474 if (opt_output_vec.size() > 1) {
475 std::cout << "TOO many output file option (-o)." << std::endl;
476 return -1;
477 }
478 if (opt_output_vec.empty()) {
479 std::string default_output_file =
482 opt_output_vec.push_back(default_output_file);
483 }
485 auto recorder = std::make_shared<Recorder>(opt_output_vec[0], opt_all,
486 opt_white_channels,
487 opt_black_channels, opt_header);
488 std::signal(SIGTERM, [](int sig) {
490 if (enable_cpu_profile) {
491 ProfilerStop();
492 }
493 if (enable_heap_profile) {
494 HeapProfilerDump("Befor shutdown");
495 HeapProfilerStop();
496 }
497 });
498
499 std::signal(SIGINT, [](int sig) {
501 if (enable_cpu_profile) {
502 ProfilerStop();
503 }
504 if (enable_heap_profile) {
505 HeapProfilerDump("Befor shutdown");
506 HeapProfilerStop();
507 }
508 });
509
510 auto base_name = std::string(argv[0]) + std::string(".prof");
511 if (enable_cpu_profile) {
512 ProfilerStart(base_name.c_str());
513 }
514 if (enable_heap_profile) {
515 HeapProfilerStart(base_name.c_str());
516 }
517 bool record_result = recorder->Start();
518 if (record_result) {
520 std::this_thread::sleep_for(std::chrono::milliseconds(100));
521 }
522 record_result = recorder->Stop();
523 }
524 return record_result ? 0 : -1;
525 } else if (command == "split") {
526 if (opt_file_vec.empty()) {
527 std::cout << "Must specify file option (-f)." << std::endl;
528 return -1;
529 }
530 if (opt_file_vec.size() > 1 || opt_output_vec.size() > 1) {
531 std::cout << "Too many input/output file option (-f/-o)." << std::endl;
532 return -1;
533 }
534 if (opt_output_vec.empty()) {
535 std::string default_output_file = opt_file_vec[0] + ".split";
536 opt_output_vec.push_back(default_output_file);
537 }
539 Spliter spliter(opt_file_vec[0], opt_output_vec[0], opt_white_channels,
540 opt_black_channels, opt_begin, opt_end);
541 bool split_result = spliter.Proc();
542 return split_result ? 0 : -1;
543 }
544
545
547 return -1;
548}
bool Display(const std::string &file)
bool PathExists(const std::string &path)
Check if the path exists.
std::string GetFileName(const std::string &path, const bool remove_extension)
std::string GetEnv(const std::string &var_name, const std::string &default_value="")
uint64_t StringToUnixSeconds(const std::string &time_str, const std::string &format_str="%Y-%m-%d %H:%M:%S")
bool PathIsAbsolute(const std::string &path)
std::string UnixSecondsToString(uint64_t unix_seconds, const std::string &format_str="%Y-%m-%d-%H:%M:%S")
bool Init(const char *binary_name, const std::string &dag_info)
std::set< std::string > black_channels
bool is_play_all_channels
std::set< std::string > files_to_play
std::set< std::string > channels_to_play