You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							155 lines
						
					
					
						
							5.1 KiB
						
					
					
				
			
		
		
	
	
							155 lines
						
					
					
						
							5.1 KiB
						
					
					
				| #include <getopt.h>
 | |
| 
 | |
| #include <iostream>
 | |
| #include <map>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| #include "common/prefix.h"
 | |
| #include "tools/replay/consoleui.h"
 | |
| #include "tools/replay/replay.h"
 | |
| #include "tools/replay/util.h"
 | |
| 
 | |
| const std::string helpText =
 | |
| R"(Usage: replay [options] [route]
 | |
| Options:
 | |
|   -a, --allow        Whitelist of services to send (comma-separated)
 | |
|   -b, --block        Blacklist of services to send (comma-separated)
 | |
|   -c, --cache        Cache <n> segments in memory. Default is 5
 | |
|   -s, --start        Start from <seconds>
 | |
|   -x, --playback     Playback <speed>
 | |
|       --demo         Use a demo route instead of providing your own
 | |
|       --auto         Auto load the route from the best available source (no video):
 | |
|                      internal, openpilotci, comma_api, car_segments, testing_closet
 | |
|   -d, --data_dir     Local directory with routes
 | |
|   -p, --prefix       Set OPENPILOT_PREFIX
 | |
|       --dcam         Load driver camera
 | |
|       --ecam         Load wide road camera
 | |
|       --no-loop      Stop at the end of the route
 | |
|       --no-cache     Turn off local cache
 | |
|       --qcam         Load qcamera
 | |
|       --no-hw-decoder Disable HW video decoding
 | |
|       --no-vipc      Do not output video
 | |
|       --all          Output all messages including uiDebug, userBookmark
 | |
|   -h, --help         Show this help message
 | |
| )";
 | |
| 
 | |
| struct ReplayConfig {
 | |
|   std::string route;
 | |
|   std::vector<std::string> allow;
 | |
|   std::vector<std::string> block;
 | |
|   std::string data_dir;
 | |
|   std::string prefix;
 | |
|   uint32_t flags = REPLAY_FLAG_NONE;
 | |
|   bool auto_source = false;
 | |
|   int start_seconds = 0;
 | |
|   int cache_segments = -1;
 | |
|   float playback_speed = -1;
 | |
| };
 | |
| 
 | |
| bool parseArgs(int argc, char *argv[], ReplayConfig &config) {
 | |
|   const struct option cli_options[] = {
 | |
|       {"allow", required_argument, nullptr, 'a'},
 | |
|       {"block", required_argument, nullptr, 'b'},
 | |
|       {"cache", required_argument, nullptr, 'c'},
 | |
|       {"start", required_argument, nullptr, 's'},
 | |
|       {"playback", required_argument, nullptr, 'x'},
 | |
|       {"demo", no_argument, nullptr, 0},
 | |
|       {"auto", no_argument, nullptr, 0},
 | |
|       {"data_dir", required_argument, nullptr, 'd'},
 | |
|       {"prefix", required_argument, nullptr, 'p'},
 | |
|       {"dcam", no_argument, nullptr, 0},
 | |
|       {"ecam", no_argument, nullptr, 0},
 | |
|       {"no-loop", no_argument, nullptr, 0},
 | |
|       {"no-cache", no_argument, nullptr, 0},
 | |
|       {"qcam", no_argument, nullptr, 0},
 | |
|       {"no-hw-decoder", no_argument, nullptr, 0},
 | |
|       {"no-vipc", no_argument, nullptr, 0},
 | |
|       {"all", no_argument, nullptr, 0},
 | |
|       {"help", no_argument, nullptr, 'h'},
 | |
|       {nullptr, 0, nullptr, 0},  // Terminating entry
 | |
|   };
 | |
| 
 | |
|   const std::map<std::string, REPLAY_FLAGS> flag_map = {
 | |
|       {"dcam", REPLAY_FLAG_DCAM},
 | |
|       {"ecam", REPLAY_FLAG_ECAM},
 | |
|       {"no-loop", REPLAY_FLAG_NO_LOOP},
 | |
|       {"no-cache", REPLAY_FLAG_NO_FILE_CACHE},
 | |
|       {"qcam", REPLAY_FLAG_QCAMERA},
 | |
|       {"no-hw-decoder", REPLAY_FLAG_NO_HW_DECODER},
 | |
|       {"no-vipc", REPLAY_FLAG_NO_VIPC},
 | |
|       {"all", REPLAY_FLAG_ALL_SERVICES},
 | |
|   };
 | |
| 
 | |
|   if (argc == 1) {
 | |
|     std::cout << helpText;
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   int opt, option_index = 0;
 | |
|   while ((opt = getopt_long(argc, argv, "a:b:c:s:x:d:p:h", cli_options, &option_index)) != -1) {
 | |
|     switch (opt) {
 | |
|       case 'a': config.allow = split(optarg, ','); break;
 | |
|       case 'b': config.block = split(optarg, ','); break;
 | |
|       case 'c': config.cache_segments = std::atoi(optarg); break;
 | |
|       case 's': config.start_seconds = std::atoi(optarg); break;
 | |
|       case 'x': config.playback_speed = std::atof(optarg); break;
 | |
|       case 'd': config.data_dir = optarg; break;
 | |
|       case 'p': config.prefix = optarg; break;
 | |
|       case 0: {
 | |
|         std::string name = cli_options[option_index].name;
 | |
|         if (name == "demo") config.route = DEMO_ROUTE;
 | |
|         else if (name == "auto") config.auto_source = true;
 | |
|         else config.flags |= flag_map.at(name);
 | |
|         break;
 | |
|       }
 | |
|       case 'h': std::cout << helpText; return false;
 | |
|       default: return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Check for a route name (first positional argument)
 | |
|   if (config.route.empty() && optind < argc) {
 | |
|     config.route = argv[optind];
 | |
|   }
 | |
| 
 | |
|   if (config.route.empty()) {
 | |
|     std::cerr << "No route provided. Use --help for usage information.\n";
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| int main(int argc, char *argv[]) {
 | |
| #ifdef __APPLE__
 | |
|   // With all sockets opened, we might hit the default limit of 256 on macOS
 | |
|   util::set_file_descriptor_limit(1024);
 | |
| #endif
 | |
| 
 | |
|   ReplayConfig config;
 | |
| 
 | |
|   if (!parseArgs(argc, argv, config)) {
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   std::unique_ptr<OpenpilotPrefix> op_prefix;
 | |
|   if (!config.prefix.empty()) {
 | |
|     op_prefix = std::make_unique<OpenpilotPrefix>(config.prefix);
 | |
|   }
 | |
| 
 | |
|   Replay replay(config.route, config.allow, config.block, nullptr, config.flags, config.data_dir, config.auto_source);
 | |
|   if (config.cache_segments > 0) {
 | |
|     replay.setSegmentCacheLimit(config.cache_segments);
 | |
|   }
 | |
|   if (config.playback_speed > 0) {
 | |
|     replay.setSpeed(std::clamp(config.playback_speed, ConsoleUI::speed_array.front(), ConsoleUI::speed_array.back()));
 | |
|   }
 | |
|   if (!replay.load()) {
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   ConsoleUI console_ui(&replay);
 | |
|   replay.start(config.start_seconds);
 | |
|   return console_ui.exec();
 | |
| }
 | |
| 
 |