• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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