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