1 #include <cstdio>
2 #include <poll.h>
3 #include <unistd.h>
4 #include <algorithm>
5 #include <regex>
6 #include <fstream>
7 #include <map>
8 #include <system_error>
9
10 #include <kms++/kms++.h>
11 #include <kms++util/kms++util.h>
12 #include <kms++util/videodevice.h>
13
14 const uint32_t NUM_SRC_BUFS=2;
15 const uint32_t NUM_DST_BUFS=2;
16
17 using namespace std;
18 using namespace kms;
19
20 static const char* usage_str =
21 "Usage: wbm2m [OPTIONS]\n\n"
22 "Options:\n"
23 " -f, --format=4CC Output format\n"
24 " -c, --crop=CROP CROP is <x>,<y>-<w>x<h>\n"
25 " -h, --help Print this help\n"
26 ;
27
28 const int bar_speed = 4;
29 const int bar_width = 10;
30
get_bar_pos(DumbFramebuffer * fb,unsigned frame_num)31 static unsigned get_bar_pos(DumbFramebuffer* fb, unsigned frame_num)
32 {
33 return (frame_num * bar_speed) % (fb->width() - bar_width + 1);
34 }
35
read_frame(DumbFramebuffer * fb,unsigned frame_num)36 static void read_frame(DumbFramebuffer* fb, unsigned frame_num)
37 {
38 static map<DumbFramebuffer*, int> s_bar_pos_map;
39
40 int old_pos = -1;
41 if (s_bar_pos_map.find(fb) != s_bar_pos_map.end())
42 old_pos = s_bar_pos_map[fb];
43
44 int pos = get_bar_pos(fb, frame_num);
45 draw_color_bar(*fb, old_pos, pos, bar_width);
46 draw_text(*fb, fb->width() / 2, 0, to_string(frame_num), RGB(255, 255, 255));
47 s_bar_pos_map[fb] = pos;
48 }
49
parse_crop(const string & crop_str,uint32_t & c_left,uint32_t & c_top,uint32_t & c_width,uint32_t & c_height)50 static void parse_crop(const string& crop_str, uint32_t& c_left, uint32_t& c_top,
51 uint32_t& c_width, uint32_t& c_height)
52 {
53 const regex crop_re("(\\d+),(\\d+)-(\\d+)x(\\d+)"); // 400,400-400x400
54
55 smatch sm;
56 if (!regex_match(crop_str, sm, crop_re))
57 EXIT("Failed to parse crop option '%s'", crop_str.c_str());
58
59 c_left = stoul(sm[1]);
60 c_top = stoul(sm[2]);
61 c_width = stoul(sm[3]);
62 c_height = stoul(sm[4]);
63 }
64
main(int argc,char ** argv)65 int main(int argc, char** argv)
66 {
67 // XXX get from args
68 const uint32_t src_width = 800;
69 const uint32_t src_height = 480;
70 const auto src_fmt = PixelFormat::XRGB8888;
71 const uint32_t num_src_frames = 10;
72
73 const uint32_t dst_width = 800;
74 const uint32_t dst_height = 480;
75 uint32_t c_top, c_left, c_width, c_height;
76
77 auto dst_fmt = PixelFormat::XRGB8888;
78 bool use_selection = false;
79
80 OptionSet optionset = {
81 Option("f|format=", [&](string s)
82 {
83 dst_fmt = FourCCToPixelFormat(s);
84 }),
85 Option("c|crop=", [&](string s)
86 {
87 parse_crop(s, c_left, c_top, c_width, c_height);
88 use_selection = true;
89 }),
90 Option("h|help", [&]()
91 {
92 puts(usage_str);
93 exit(-1);
94 }),
95 };
96
97 optionset.parse(argc, argv);
98
99 if (optionset.params().size() > 0) {
100 puts(usage_str);
101 exit(-1);
102 }
103
104 const string filename = sformat("wb-out-%ux%u_%4.4s.raw", dst_width, dst_height,
105 PixelFormatToFourCC(dst_fmt).c_str());
106
107 VideoDevice vid("/dev/video10");
108
109 Card card;
110
111 uint32_t src_frame_num = 0;
112 uint32_t dst_frame_num = 0;
113
114 VideoStreamer* out = vid.get_output_streamer();
115 VideoStreamer* in = vid.get_capture_streamer();
116
117 out->set_format(src_fmt, src_width, src_height);
118 in->set_format(dst_fmt, dst_width, dst_height);
119
120 if (use_selection) {
121 out->set_selection(c_left, c_top, c_width, c_height);
122 printf("crop -> %u,%u-%ux%u\n", c_left, c_top, c_width, c_height);
123 }
124
125 out->set_queue_size(NUM_SRC_BUFS);
126 in->set_queue_size(NUM_DST_BUFS);
127
128
129 for (unsigned i = 0; i < min(NUM_SRC_BUFS, num_src_frames); ++i) {
130 auto fb = new DumbFramebuffer(card, src_width, src_height, src_fmt);
131
132 read_frame(fb, src_frame_num++);
133
134 out->queue(fb);
135 }
136
137 for (unsigned i = 0; i < min(NUM_DST_BUFS, num_src_frames); ++i) {
138 auto fb = new DumbFramebuffer(card, dst_width, dst_height, dst_fmt);
139 in->queue(fb);
140 }
141
142 vector<pollfd> fds(3);
143
144 fds[0].fd = 0;
145 fds[0].events = POLLIN;
146 fds[1].fd = vid.fd();
147 fds[1].events = POLLIN;
148 fds[2].fd = card.fd();
149 fds[2].events = POLLIN;
150
151 ofstream os(filename, ofstream::binary);
152
153 out->stream_on();
154 in->stream_on();
155
156 while (true) {
157 int r = poll(fds.data(), fds.size(), -1);
158 ASSERT(r > 0);
159
160 if (fds[0].revents != 0)
161 break;
162
163 if (fds[1].revents) {
164 fds[1].revents = 0;
165
166
167 try {
168 DumbFramebuffer *dst_fb = in->dequeue();
169 printf("Writing frame %u\n", dst_frame_num);
170 for (unsigned i = 0; i < dst_fb->num_planes(); ++i)
171 os.write((char*)dst_fb->map(i), dst_fb->size(i));
172 in->queue(dst_fb);
173
174 dst_frame_num++;
175
176 if (dst_frame_num >= num_src_frames)
177 break;
178
179 } catch (system_error& se) {
180 if (se.code() != errc::resource_unavailable_try_again)
181 FAIL("dequeue failed: %s", se.what());
182
183 break;
184 }
185
186 DumbFramebuffer *src_fb = out->dequeue();
187
188 if (src_frame_num < num_src_frames) {
189 read_frame(src_fb, src_frame_num++);
190 out->queue(src_fb);
191 }
192 }
193
194 if (fds[2].revents) {
195 fds[2].revents = 0;
196 }
197 }
198
199 printf("exiting...\n");
200 }
201