blob: ac24d68d065a97d923fc90385eb19a51e8d7272f [file] [log] [blame]
Ravago Jones3b4fd912023-03-18 13:35:17 -07001#include <unistd.h>
2
3#include <cstdlib>
4
Austin Schuh99f7c6a2024-06-25 22:07:44 -07005#include "absl/flags/flag.h"
6#include "absl/log/check.h"
7#include "absl/log/log.h"
Ravago Jones3b4fd912023-03-18 13:35:17 -07008
9#include "aos/events/logging/log_reader.h"
10#include "aos/events/simulated_event_loop.h"
11#include "aos/init.h"
12#include "aos/scoped/scoped_fd.h"
13#include "frc971/vision/vision_generated.h"
14
Austin Schuh99f7c6a2024-06-25 22:07:44 -070015ABSL_FLAG(std::string, channel, "/camera", "Channel name for the image.");
16ABSL_FLAG(int32_t, width, 1280, "Width of the image");
17ABSL_FLAG(int32_t, height, 720, "Height of the image");
18ABSL_FLAG(std::string, ffmpeg_binary, "external/ffmpeg/ffmpeg",
19 "The path to the ffmpeg binary");
20ABSL_FLAG(std::string, output_path, "video_ripper_output.mp4",
21 "The path to output the mp4 video");
22ABSL_FLAG(bool, flip, true, "If true, rotate the video 180 deg.");
Ravago Jones3b4fd912023-03-18 13:35:17 -070023
24// Replays a log and dumps the contents of /camera frc971.vision.CameraImage
25// directly to stdout.
26int main(int argc, char *argv[]) {
27 aos::InitGoogle(&argc, &argv);
28 const std::vector<aos::logger::LogFile> logfiles =
29 aos::logger::SortParts(aos::logger::FindLogs(argc, argv));
30 CHECK(!logfiles.empty());
31
32 // Start ffmpeg
33 std::stringstream command;
Austin Schuh99f7c6a2024-06-25 22:07:44 -070034 command << absl::GetFlag(FLAGS_ffmpeg_binary);
Ravago Jones3b4fd912023-03-18 13:35:17 -070035 command << " -framerate 30 -f rawvideo -pix_fmt yuyv422";
Austin Schuh99f7c6a2024-06-25 22:07:44 -070036 command << " -s " << absl::GetFlag(FLAGS_width) << "x"
37 << absl::GetFlag(FLAGS_height);
Ravago Jones3b4fd912023-03-18 13:35:17 -070038 command << " -i pipe:";
39 command << " -c:v libx264 -f mp4";
Austin Schuh99f7c6a2024-06-25 22:07:44 -070040 if (absl::GetFlag(FLAGS_flip)) {
Ravago Jones3b4fd912023-03-18 13:35:17 -070041 command << " -vf rotate=PI";
42 }
Austin Schuh99f7c6a2024-06-25 22:07:44 -070043 command << " \"" << absl::GetFlag(FLAGS_output_path) << "\"";
Ravago Jones3b4fd912023-03-18 13:35:17 -070044
45 FILE *stream = popen(command.str().c_str(), "w");
46
47 const std::string replay_node = logfiles.at(0).logger_node;
48 LOG(INFO) << "Replaying as \"" << replay_node << "\"";
49
50 aos::logger::LogReader reader(logfiles, nullptr);
51 aos::SimulatedEventLoopFactory factory(reader.configuration());
52 reader.RegisterWithoutStarting(&factory);
53
54 const aos::Node *node =
55 (replay_node.empty() ||
56 !aos::configuration::MultiNode(reader.configuration()))
57 ? nullptr
58 : aos::configuration::GetNode(reader.configuration(), replay_node);
59
60 std::unique_ptr<aos::EventLoop> event_loop;
61 factory.GetNodeEventLoopFactory(node)->OnStartup([&stream, &event_loop,
62 &reader, node]() {
63 event_loop =
64 reader.event_loop_factory()->MakeEventLoop("video_ripper", node);
65 event_loop->MakeWatcher(
Austin Schuh99f7c6a2024-06-25 22:07:44 -070066 absl::GetFlag(FLAGS_channel),
67 [&stream](const frc971::vision::CameraImage &image) {
68 CHECK_EQ(absl::GetFlag(FLAGS_width), image.cols())
Ravago Jones3b4fd912023-03-18 13:35:17 -070069 << "Image width needs to match the images in the logfile";
Austin Schuh99f7c6a2024-06-25 22:07:44 -070070 CHECK_EQ(absl::GetFlag(FLAGS_height), image.rows())
Ravago Jones3b4fd912023-03-18 13:35:17 -070071 << "Image width needs to match the images in the logfile";
72
73 const size_t bytes_written =
74 write(fileno(stream), image.data()->data(), image.data()->size());
75 PCHECK(bytes_written == image.data()->size());
76 });
77 });
78
79 reader.event_loop_factory()->Run();
80 reader.Deregister();
81
82 pclose(stream);
83}