xref: /aosp_15_r20/external/libkmsxx/utils/omap-wbcap.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
1*f0687c8aSRaman Tenneti #include <cstdio>
2*f0687c8aSRaman Tenneti #include <poll.h>
3*f0687c8aSRaman Tenneti #include <unistd.h>
4*f0687c8aSRaman Tenneti #include <algorithm>
5*f0687c8aSRaman Tenneti #include <fstream>
6*f0687c8aSRaman Tenneti 
7*f0687c8aSRaman Tenneti #include <kms++/kms++.h>
8*f0687c8aSRaman Tenneti #include <kms++util/kms++util.h>
9*f0687c8aSRaman Tenneti #include <kms++util/videodevice.h>
10*f0687c8aSRaman Tenneti 
11*f0687c8aSRaman Tenneti #define CAMERA_BUF_QUEUE_SIZE 5
12*f0687c8aSRaman Tenneti 
13*f0687c8aSRaman Tenneti using namespace std;
14*f0687c8aSRaman Tenneti using namespace kms;
15*f0687c8aSRaman Tenneti 
16*f0687c8aSRaman Tenneti static vector<DumbFramebuffer*> s_fbs;
17*f0687c8aSRaman Tenneti static vector<DumbFramebuffer*> s_free_fbs;
18*f0687c8aSRaman Tenneti static vector<DumbFramebuffer*> s_wb_fbs;
19*f0687c8aSRaman Tenneti static vector<DumbFramebuffer*> s_ready_fbs;
20*f0687c8aSRaman Tenneti 
21*f0687c8aSRaman Tenneti class WBStreamer
22*f0687c8aSRaman Tenneti {
23*f0687c8aSRaman Tenneti public:
WBStreamer(VideoStreamer * streamer,Crtc * crtc,PixelFormat pixfmt)24*f0687c8aSRaman Tenneti 	WBStreamer(VideoStreamer* streamer, Crtc* crtc, PixelFormat pixfmt)
25*f0687c8aSRaman Tenneti 		: m_capdev(*streamer)
26*f0687c8aSRaman Tenneti 	{
27*f0687c8aSRaman Tenneti 		Videomode m = crtc->mode();
28*f0687c8aSRaman Tenneti 
29*f0687c8aSRaman Tenneti 		m_capdev.set_port(crtc->idx());
30*f0687c8aSRaman Tenneti 		m_capdev.set_format(pixfmt, m.hdisplay, m.vdisplay / (m.interlace() ? 2 : 1));
31*f0687c8aSRaman Tenneti 		m_capdev.set_queue_size(s_fbs.size());
32*f0687c8aSRaman Tenneti 
33*f0687c8aSRaman Tenneti 		for (auto fb : s_free_fbs) {
34*f0687c8aSRaman Tenneti 			m_capdev.queue(fb);
35*f0687c8aSRaman Tenneti 			s_wb_fbs.push_back(fb);
36*f0687c8aSRaman Tenneti 		}
37*f0687c8aSRaman Tenneti 
38*f0687c8aSRaman Tenneti 		s_free_fbs.clear();
39*f0687c8aSRaman Tenneti 	}
40*f0687c8aSRaman Tenneti 
~WBStreamer()41*f0687c8aSRaman Tenneti 	~WBStreamer()
42*f0687c8aSRaman Tenneti 	{
43*f0687c8aSRaman Tenneti 	}
44*f0687c8aSRaman Tenneti 
45*f0687c8aSRaman Tenneti 	WBStreamer(const WBStreamer& other) = delete;
46*f0687c8aSRaman Tenneti 	WBStreamer& operator=(const WBStreamer& other) = delete;
47*f0687c8aSRaman Tenneti 
fd() const48*f0687c8aSRaman Tenneti 	int fd() const { return m_capdev.fd(); }
49*f0687c8aSRaman Tenneti 
start_streaming()50*f0687c8aSRaman Tenneti 	void start_streaming()
51*f0687c8aSRaman Tenneti 	{
52*f0687c8aSRaman Tenneti 		m_capdev.stream_on();
53*f0687c8aSRaman Tenneti 	}
54*f0687c8aSRaman Tenneti 
stop_streaming()55*f0687c8aSRaman Tenneti 	void stop_streaming()
56*f0687c8aSRaman Tenneti 	{
57*f0687c8aSRaman Tenneti 		m_capdev.stream_off();
58*f0687c8aSRaman Tenneti 	}
59*f0687c8aSRaman Tenneti 
Dequeue()60*f0687c8aSRaman Tenneti 	DumbFramebuffer* Dequeue()
61*f0687c8aSRaman Tenneti 	{
62*f0687c8aSRaman Tenneti 		auto fb = m_capdev.dequeue();
63*f0687c8aSRaman Tenneti 
64*f0687c8aSRaman Tenneti 		auto iter = find(s_wb_fbs.begin(), s_wb_fbs.end(), fb);
65*f0687c8aSRaman Tenneti 		s_wb_fbs.erase(iter);
66*f0687c8aSRaman Tenneti 
67*f0687c8aSRaman Tenneti 		s_ready_fbs.insert(s_ready_fbs.begin(), fb);
68*f0687c8aSRaman Tenneti 
69*f0687c8aSRaman Tenneti 		return fb;
70*f0687c8aSRaman Tenneti 	}
71*f0687c8aSRaman Tenneti 
Queue()72*f0687c8aSRaman Tenneti 	void Queue()
73*f0687c8aSRaman Tenneti 	{
74*f0687c8aSRaman Tenneti 		if (s_free_fbs.size() == 0)
75*f0687c8aSRaman Tenneti 			return;
76*f0687c8aSRaman Tenneti 
77*f0687c8aSRaman Tenneti 		auto fb = s_free_fbs.back();
78*f0687c8aSRaman Tenneti 		s_free_fbs.pop_back();
79*f0687c8aSRaman Tenneti 
80*f0687c8aSRaman Tenneti 		m_capdev.queue(fb);
81*f0687c8aSRaman Tenneti 
82*f0687c8aSRaman Tenneti 		s_wb_fbs.insert(s_wb_fbs.begin(), fb);
83*f0687c8aSRaman Tenneti 	}
84*f0687c8aSRaman Tenneti 
85*f0687c8aSRaman Tenneti private:
86*f0687c8aSRaman Tenneti 	VideoStreamer& m_capdev;
87*f0687c8aSRaman Tenneti };
88*f0687c8aSRaman Tenneti 
89*f0687c8aSRaman Tenneti class WBFlipState : private PageFlipHandlerBase
90*f0687c8aSRaman Tenneti {
91*f0687c8aSRaman Tenneti public:
WBFlipState(Card & card,Crtc * crtc,Plane * plane)92*f0687c8aSRaman Tenneti 	WBFlipState(Card& card, Crtc* crtc, Plane* plane)
93*f0687c8aSRaman Tenneti 		: m_card(card), m_crtc(crtc), m_plane(plane)
94*f0687c8aSRaman Tenneti 	{
95*f0687c8aSRaman Tenneti 		auto fb = s_ready_fbs.back();
96*f0687c8aSRaman Tenneti 		s_ready_fbs.pop_back();
97*f0687c8aSRaman Tenneti 
98*f0687c8aSRaman Tenneti 		AtomicReq req(m_card);
99*f0687c8aSRaman Tenneti 
100*f0687c8aSRaman Tenneti 		req.add(m_plane, "CRTC_ID", m_crtc->id());
101*f0687c8aSRaman Tenneti 		req.add(m_plane, "FB_ID", fb->id());
102*f0687c8aSRaman Tenneti 
103*f0687c8aSRaman Tenneti 		req.add(m_plane, "CRTC_X", 0);
104*f0687c8aSRaman Tenneti 		req.add(m_plane, "CRTC_Y", 0);
105*f0687c8aSRaman Tenneti 		req.add(m_plane, "CRTC_W", min((uint32_t)m_crtc->mode().hdisplay, fb->width()));
106*f0687c8aSRaman Tenneti 		req.add(m_plane, "CRTC_H", min((uint32_t)m_crtc->mode().vdisplay, fb->height()));
107*f0687c8aSRaman Tenneti 
108*f0687c8aSRaman Tenneti 		req.add(m_plane, "SRC_X", 0);
109*f0687c8aSRaman Tenneti 		req.add(m_plane, "SRC_Y", 0);
110*f0687c8aSRaman Tenneti 		req.add(m_plane, "SRC_W", fb->width() << 16);
111*f0687c8aSRaman Tenneti 		req.add(m_plane, "SRC_H", fb->height() << 16);
112*f0687c8aSRaman Tenneti 
113*f0687c8aSRaman Tenneti 		int r = req.commit_sync();
114*f0687c8aSRaman Tenneti 		FAIL_IF(r, "initial plane setup failed");
115*f0687c8aSRaman Tenneti 
116*f0687c8aSRaman Tenneti 		m_current_fb = fb;
117*f0687c8aSRaman Tenneti 	}
118*f0687c8aSRaman Tenneti 
queue_next()119*f0687c8aSRaman Tenneti 	void queue_next()
120*f0687c8aSRaman Tenneti 	{
121*f0687c8aSRaman Tenneti 		if (m_queued_fb)
122*f0687c8aSRaman Tenneti 			return;
123*f0687c8aSRaman Tenneti 
124*f0687c8aSRaman Tenneti 		if (s_ready_fbs.size() == 0)
125*f0687c8aSRaman Tenneti 			return;
126*f0687c8aSRaman Tenneti 
127*f0687c8aSRaman Tenneti 		auto fb = s_ready_fbs.back();
128*f0687c8aSRaman Tenneti 		s_ready_fbs.pop_back();
129*f0687c8aSRaman Tenneti 
130*f0687c8aSRaman Tenneti 		AtomicReq req(m_card);
131*f0687c8aSRaman Tenneti 		req.add(m_plane, "FB_ID", fb->id());
132*f0687c8aSRaman Tenneti 
133*f0687c8aSRaman Tenneti 		int r = req.commit(this);
134*f0687c8aSRaman Tenneti 		if (r)
135*f0687c8aSRaman Tenneti 			EXIT("Flip commit failed: %d\n", r);
136*f0687c8aSRaman Tenneti 
137*f0687c8aSRaman Tenneti 		m_queued_fb = fb;
138*f0687c8aSRaman Tenneti 	}
139*f0687c8aSRaman Tenneti 
140*f0687c8aSRaman Tenneti private:
handle_page_flip(uint32_t frame,double time)141*f0687c8aSRaman Tenneti 	void handle_page_flip(uint32_t frame, double time)
142*f0687c8aSRaman Tenneti 	{
143*f0687c8aSRaman Tenneti 		if (m_queued_fb) {
144*f0687c8aSRaman Tenneti 			if (m_current_fb)
145*f0687c8aSRaman Tenneti 				s_free_fbs.insert(s_free_fbs.begin(), m_current_fb);
146*f0687c8aSRaman Tenneti 
147*f0687c8aSRaman Tenneti 			m_current_fb = m_queued_fb;
148*f0687c8aSRaman Tenneti 			m_queued_fb = nullptr;
149*f0687c8aSRaman Tenneti 		}
150*f0687c8aSRaman Tenneti 
151*f0687c8aSRaman Tenneti 		queue_next();
152*f0687c8aSRaman Tenneti 	}
153*f0687c8aSRaman Tenneti 
154*f0687c8aSRaman Tenneti 	Card& m_card;
155*f0687c8aSRaman Tenneti 	Crtc* m_crtc;
156*f0687c8aSRaman Tenneti 	Plane* m_plane;
157*f0687c8aSRaman Tenneti 
158*f0687c8aSRaman Tenneti 	DumbFramebuffer* m_current_fb = nullptr;
159*f0687c8aSRaman Tenneti 	DumbFramebuffer* m_queued_fb = nullptr;
160*f0687c8aSRaman Tenneti };
161*f0687c8aSRaman Tenneti 
162*f0687c8aSRaman Tenneti class BarFlipState : private PageFlipHandlerBase
163*f0687c8aSRaman Tenneti {
164*f0687c8aSRaman Tenneti public:
BarFlipState(Card & card,Crtc * crtc,Plane * plane,uint32_t width,uint32_t height)165*f0687c8aSRaman Tenneti 	BarFlipState(Card& card, Crtc* crtc, Plane* plane, uint32_t width, uint32_t height)
166*f0687c8aSRaman Tenneti 		: m_card(card), m_crtc(crtc), m_plane(plane)
167*f0687c8aSRaman Tenneti 	{
168*f0687c8aSRaman Tenneti 		for (unsigned i = 0; i < s_num_buffers; ++i)
169*f0687c8aSRaman Tenneti 			m_fbs[i] = new DumbFramebuffer(card, width, height, PixelFormat::XRGB8888);
170*f0687c8aSRaman Tenneti 	}
171*f0687c8aSRaman Tenneti 
~BarFlipState()172*f0687c8aSRaman Tenneti 	~BarFlipState()
173*f0687c8aSRaman Tenneti 	{
174*f0687c8aSRaman Tenneti 		for (unsigned i = 0; i < s_num_buffers; ++i)
175*f0687c8aSRaman Tenneti 			delete m_fbs[i];
176*f0687c8aSRaman Tenneti 	}
177*f0687c8aSRaman Tenneti 
start_flipping()178*f0687c8aSRaman Tenneti 	void start_flipping()
179*f0687c8aSRaman Tenneti 	{
180*f0687c8aSRaman Tenneti 		m_frame_num = 0;
181*f0687c8aSRaman Tenneti 		queue_next();
182*f0687c8aSRaman Tenneti 	}
183*f0687c8aSRaman Tenneti 
184*f0687c8aSRaman Tenneti private:
handle_page_flip(uint32_t frame,double time)185*f0687c8aSRaman Tenneti 	void handle_page_flip(uint32_t frame, double time)
186*f0687c8aSRaman Tenneti 	{
187*f0687c8aSRaman Tenneti 		m_frame_num++;
188*f0687c8aSRaman Tenneti 		queue_next();
189*f0687c8aSRaman Tenneti 	}
190*f0687c8aSRaman Tenneti 
get_bar_pos(DumbFramebuffer * fb,unsigned frame_num)191*f0687c8aSRaman Tenneti 	static unsigned get_bar_pos(DumbFramebuffer* fb, unsigned frame_num)
192*f0687c8aSRaman Tenneti 	{
193*f0687c8aSRaman Tenneti 		return (frame_num * bar_speed) % (fb->width() - bar_width + 1);
194*f0687c8aSRaman Tenneti 	}
195*f0687c8aSRaman Tenneti 
draw_bar(DumbFramebuffer * fb,unsigned frame_num)196*f0687c8aSRaman Tenneti 	void draw_bar(DumbFramebuffer* fb, unsigned frame_num)
197*f0687c8aSRaman Tenneti 	{
198*f0687c8aSRaman Tenneti 		int old_xpos = frame_num < s_num_buffers ? -1 : get_bar_pos(fb, frame_num - s_num_buffers);
199*f0687c8aSRaman Tenneti 		int new_xpos = get_bar_pos(fb, frame_num);
200*f0687c8aSRaman Tenneti 
201*f0687c8aSRaman Tenneti 		draw_color_bar(*fb, old_xpos, new_xpos, bar_width);
202*f0687c8aSRaman Tenneti 		draw_text(*fb, fb->width() / 2, 0, to_string(frame_num), RGB(255, 255, 255));
203*f0687c8aSRaman Tenneti 	}
204*f0687c8aSRaman Tenneti 
queue_next()205*f0687c8aSRaman Tenneti 	void queue_next()
206*f0687c8aSRaman Tenneti 	{
207*f0687c8aSRaman Tenneti 		AtomicReq req(m_card);
208*f0687c8aSRaman Tenneti 
209*f0687c8aSRaman Tenneti 		unsigned cur = m_frame_num % s_num_buffers;
210*f0687c8aSRaman Tenneti 
211*f0687c8aSRaman Tenneti 		auto fb = m_fbs[cur];
212*f0687c8aSRaman Tenneti 
213*f0687c8aSRaman Tenneti 		draw_bar(fb, m_frame_num);
214*f0687c8aSRaman Tenneti 
215*f0687c8aSRaman Tenneti 		req.add(m_plane, {
216*f0687c8aSRaman Tenneti 					 { "CRTC_ID", m_crtc->id() },
217*f0687c8aSRaman Tenneti 					 { "FB_ID", fb->id() },
218*f0687c8aSRaman Tenneti 
219*f0687c8aSRaman Tenneti 					 { "CRTC_X", 0 },
220*f0687c8aSRaman Tenneti 					 { "CRTC_Y", 0 },
221*f0687c8aSRaman Tenneti 					 { "CRTC_W", min((uint32_t)m_crtc->mode().hdisplay, fb->width()) },
222*f0687c8aSRaman Tenneti 					 { "CRTC_H", min((uint32_t)m_crtc->mode().vdisplay, fb->height()) },
223*f0687c8aSRaman Tenneti 
224*f0687c8aSRaman Tenneti 					 { "SRC_X", 0 },
225*f0687c8aSRaman Tenneti 					 { "SRC_Y", 0 },
226*f0687c8aSRaman Tenneti 					 { "SRC_W", fb->width() << 16 },
227*f0687c8aSRaman Tenneti 					 { "SRC_H", fb->height() << 16 },
228*f0687c8aSRaman Tenneti 				 });
229*f0687c8aSRaman Tenneti 
230*f0687c8aSRaman Tenneti 		int r = req.commit(this);
231*f0687c8aSRaman Tenneti 		if (r)
232*f0687c8aSRaman Tenneti 			EXIT("Flip commit failed: %d\n", r);
233*f0687c8aSRaman Tenneti 	}
234*f0687c8aSRaman Tenneti 
235*f0687c8aSRaman Tenneti 	static const unsigned s_num_buffers = 3;
236*f0687c8aSRaman Tenneti 
237*f0687c8aSRaman Tenneti 	DumbFramebuffer* m_fbs[s_num_buffers];
238*f0687c8aSRaman Tenneti 
239*f0687c8aSRaman Tenneti 	Card& m_card;
240*f0687c8aSRaman Tenneti 	Crtc* m_crtc;
241*f0687c8aSRaman Tenneti 	Plane* m_plane;
242*f0687c8aSRaman Tenneti 
243*f0687c8aSRaman Tenneti 	unsigned m_frame_num;
244*f0687c8aSRaman Tenneti 
245*f0687c8aSRaman Tenneti 	static const unsigned bar_width = 20;
246*f0687c8aSRaman Tenneti 	static const unsigned bar_speed = 8;
247*f0687c8aSRaman Tenneti };
248*f0687c8aSRaman Tenneti 
249*f0687c8aSRaman Tenneti static const char* usage_str =
250*f0687c8aSRaman Tenneti 	"Usage: wbcap [OPTIONS]\n\n"
251*f0687c8aSRaman Tenneti 	"Options:\n"
252*f0687c8aSRaman Tenneti 	"  -s, --src=CONN            Source connector\n"
253*f0687c8aSRaman Tenneti 	"  -d, --dst=CONN            Destination connector\n"
254*f0687c8aSRaman Tenneti 	"  -m, --smode=MODE          Source connector videomode\n"
255*f0687c8aSRaman Tenneti 	"  -M, --dmode=MODE          Destination connector videomode\n"
256*f0687c8aSRaman Tenneti 	"  -f, --format=4CC          Format\n"
257*f0687c8aSRaman Tenneti 	"  -w, --write               Write captured frames to wbcap.raw file\n"
258*f0687c8aSRaman Tenneti 	"  -h, --help                Print this help\n";
259*f0687c8aSRaman Tenneti 
main(int argc,char ** argv)260*f0687c8aSRaman Tenneti int main(int argc, char** argv)
261*f0687c8aSRaman Tenneti {
262*f0687c8aSRaman Tenneti 	string src_conn_name;
263*f0687c8aSRaman Tenneti 	string src_mode_name;
264*f0687c8aSRaman Tenneti 	string dst_conn_name;
265*f0687c8aSRaman Tenneti 	string dst_mode_name;
266*f0687c8aSRaman Tenneti 	PixelFormat pixfmt = PixelFormat::XRGB8888;
267*f0687c8aSRaman Tenneti 	bool write_file = false;
268*f0687c8aSRaman Tenneti 
269*f0687c8aSRaman Tenneti 	OptionSet optionset = {
270*f0687c8aSRaman Tenneti 		Option("s|src=", [&](string s) {
271*f0687c8aSRaman Tenneti 			src_conn_name = s;
272*f0687c8aSRaman Tenneti 		}),
273*f0687c8aSRaman Tenneti 		Option("m|smode=", [&](string s) {
274*f0687c8aSRaman Tenneti 			src_mode_name = s;
275*f0687c8aSRaman Tenneti 		}),
276*f0687c8aSRaman Tenneti 		Option("d|dst=", [&](string s) {
277*f0687c8aSRaman Tenneti 			dst_conn_name = s;
278*f0687c8aSRaman Tenneti 		}),
279*f0687c8aSRaman Tenneti 		Option("M|dmode=", [&](string s) {
280*f0687c8aSRaman Tenneti 			dst_mode_name = s;
281*f0687c8aSRaman Tenneti 		}),
282*f0687c8aSRaman Tenneti 		Option("f|format=", [&](string s) {
283*f0687c8aSRaman Tenneti 			pixfmt = FourCCToPixelFormat(s);
284*f0687c8aSRaman Tenneti 		}),
285*f0687c8aSRaman Tenneti 		Option("w|write", [&]() {
286*f0687c8aSRaman Tenneti 			write_file = true;
287*f0687c8aSRaman Tenneti 		}),
288*f0687c8aSRaman Tenneti 		Option("h|help", [&]() {
289*f0687c8aSRaman Tenneti 			puts(usage_str);
290*f0687c8aSRaman Tenneti 			exit(-1);
291*f0687c8aSRaman Tenneti 		}),
292*f0687c8aSRaman Tenneti 	};
293*f0687c8aSRaman Tenneti 
294*f0687c8aSRaman Tenneti 	optionset.parse(argc, argv);
295*f0687c8aSRaman Tenneti 
296*f0687c8aSRaman Tenneti 	if (optionset.params().size() > 0) {
297*f0687c8aSRaman Tenneti 		puts(usage_str);
298*f0687c8aSRaman Tenneti 		exit(-1);
299*f0687c8aSRaman Tenneti 	}
300*f0687c8aSRaman Tenneti 
301*f0687c8aSRaman Tenneti 	if (src_conn_name.empty())
302*f0687c8aSRaman Tenneti 		EXIT("No source connector defined");
303*f0687c8aSRaman Tenneti 
304*f0687c8aSRaman Tenneti 	if (dst_conn_name.empty())
305*f0687c8aSRaman Tenneti 		EXIT("No destination connector defined");
306*f0687c8aSRaman Tenneti 
307*f0687c8aSRaman Tenneti 	VideoDevice vid("/dev/video11");
308*f0687c8aSRaman Tenneti 
309*f0687c8aSRaman Tenneti 	Card card;
310*f0687c8aSRaman Tenneti 	ResourceManager resman(card);
311*f0687c8aSRaman Tenneti 
312*f0687c8aSRaman Tenneti 	card.disable_all();
313*f0687c8aSRaman Tenneti 
314*f0687c8aSRaman Tenneti 	auto src_conn = resman.reserve_connector(src_conn_name);
315*f0687c8aSRaman Tenneti 	auto src_crtc = resman.reserve_crtc(src_conn);
316*f0687c8aSRaman Tenneti 	auto src_plane = resman.reserve_generic_plane(src_crtc, pixfmt);
317*f0687c8aSRaman Tenneti 	FAIL_IF(!src_plane, "Plane not found");
318*f0687c8aSRaman Tenneti 	Videomode src_mode = src_mode_name.empty() ? src_conn->get_default_mode() : src_conn->get_mode(src_mode_name);
319*f0687c8aSRaman Tenneti 	src_crtc->set_mode(src_conn, src_mode);
320*f0687c8aSRaman Tenneti 
321*f0687c8aSRaman Tenneti 	auto dst_conn = resman.reserve_connector(dst_conn_name);
322*f0687c8aSRaman Tenneti 	auto dst_crtc = resman.reserve_crtc(dst_conn);
323*f0687c8aSRaman Tenneti 	auto dst_plane = resman.reserve_overlay_plane(dst_crtc, pixfmt);
324*f0687c8aSRaman Tenneti 	FAIL_IF(!dst_plane, "Plane not found");
325*f0687c8aSRaman Tenneti 	Videomode dst_mode = dst_mode_name.empty() ? dst_conn->get_default_mode() : dst_conn->get_mode(dst_mode_name);
326*f0687c8aSRaman Tenneti 	dst_crtc->set_mode(dst_conn, dst_mode);
327*f0687c8aSRaman Tenneti 
328*f0687c8aSRaman Tenneti 	uint32_t src_width = src_mode.hdisplay;
329*f0687c8aSRaman Tenneti 	uint32_t src_height = src_mode.vdisplay;
330*f0687c8aSRaman Tenneti 
331*f0687c8aSRaman Tenneti 	uint32_t dst_width = src_mode.hdisplay;
332*f0687c8aSRaman Tenneti 	uint32_t dst_height = src_mode.vdisplay;
333*f0687c8aSRaman Tenneti 	if (src_mode.interlace())
334*f0687c8aSRaman Tenneti 		dst_height /= 2;
335*f0687c8aSRaman Tenneti 
336*f0687c8aSRaman Tenneti 	printf("src %s, crtc %s\n", src_conn->fullname().c_str(), src_mode.to_string_short().c_str());
337*f0687c8aSRaman Tenneti 
338*f0687c8aSRaman Tenneti 	printf("dst %s, crtc %s\n", dst_conn->fullname().c_str(), dst_mode.to_string_short().c_str());
339*f0687c8aSRaman Tenneti 
340*f0687c8aSRaman Tenneti 	printf("src_fb %ux%u, dst_fb %ux%u\n", src_width, src_height, dst_width, dst_height);
341*f0687c8aSRaman Tenneti 
342*f0687c8aSRaman Tenneti 	for (int i = 0; i < CAMERA_BUF_QUEUE_SIZE; ++i) {
343*f0687c8aSRaman Tenneti 		auto fb = new DumbFramebuffer(card, dst_width, dst_height, pixfmt);
344*f0687c8aSRaman Tenneti 		s_fbs.push_back(fb);
345*f0687c8aSRaman Tenneti 		s_free_fbs.push_back(fb);
346*f0687c8aSRaman Tenneti 	}
347*f0687c8aSRaman Tenneti 
348*f0687c8aSRaman Tenneti 	// get one fb for initial setup
349*f0687c8aSRaman Tenneti 	s_ready_fbs.push_back(s_free_fbs.back());
350*f0687c8aSRaman Tenneti 	s_free_fbs.pop_back();
351*f0687c8aSRaman Tenneti 
352*f0687c8aSRaman Tenneti 	// This draws a moving bar to SRC display
353*f0687c8aSRaman Tenneti 	BarFlipState barflipper(card, src_crtc, src_plane, src_width, src_height);
354*f0687c8aSRaman Tenneti 	barflipper.start_flipping();
355*f0687c8aSRaman Tenneti 
356*f0687c8aSRaman Tenneti 	// This shows the captured SRC frames on DST display
357*f0687c8aSRaman Tenneti 	WBFlipState wbflipper(card, dst_crtc, dst_plane);
358*f0687c8aSRaman Tenneti 
359*f0687c8aSRaman Tenneti 	WBStreamer wb(vid.get_capture_streamer(), src_crtc, pixfmt);
360*f0687c8aSRaman Tenneti 	wb.start_streaming();
361*f0687c8aSRaman Tenneti 
362*f0687c8aSRaman Tenneti 	vector<pollfd> fds(3);
363*f0687c8aSRaman Tenneti 
364*f0687c8aSRaman Tenneti 	fds[0].fd = 0;
365*f0687c8aSRaman Tenneti 	fds[0].events = POLLIN;
366*f0687c8aSRaman Tenneti 	fds[1].fd = wb.fd();
367*f0687c8aSRaman Tenneti 	fds[1].events = POLLIN;
368*f0687c8aSRaman Tenneti 	fds[2].fd = card.fd();
369*f0687c8aSRaman Tenneti 	fds[2].events = POLLIN;
370*f0687c8aSRaman Tenneti 
371*f0687c8aSRaman Tenneti 	uint32_t dst_frame_num = 0;
372*f0687c8aSRaman Tenneti 
373*f0687c8aSRaman Tenneti 	const string filename = "wbcap.raw";
374*f0687c8aSRaman Tenneti 	unique_ptr<ofstream> os;
375*f0687c8aSRaman Tenneti 	if (write_file)
376*f0687c8aSRaman Tenneti 		os = unique_ptr<ofstream>(new ofstream(filename, ofstream::binary));
377*f0687c8aSRaman Tenneti 
378*f0687c8aSRaman Tenneti 	while (true) {
379*f0687c8aSRaman Tenneti 		int r = poll(fds.data(), fds.size(), -1);
380*f0687c8aSRaman Tenneti 		ASSERT(r > 0);
381*f0687c8aSRaman Tenneti 
382*f0687c8aSRaman Tenneti 		if (fds[0].revents != 0)
383*f0687c8aSRaman Tenneti 			break;
384*f0687c8aSRaman Tenneti 
385*f0687c8aSRaman Tenneti 		if (fds[1].revents) {
386*f0687c8aSRaman Tenneti 			fds[1].revents = 0;
387*f0687c8aSRaman Tenneti 
388*f0687c8aSRaman Tenneti 			DumbFramebuffer* fb = wb.Dequeue();
389*f0687c8aSRaman Tenneti 
390*f0687c8aSRaman Tenneti 			if (write_file) {
391*f0687c8aSRaman Tenneti 				printf("Writing frame %u to %s\n", dst_frame_num, filename.c_str());
392*f0687c8aSRaman Tenneti 
393*f0687c8aSRaman Tenneti 				for (unsigned i = 0; i < fb->num_planes(); ++i)
394*f0687c8aSRaman Tenneti 					os->write((char*)fb->map(i), fb->size(i));
395*f0687c8aSRaman Tenneti 
396*f0687c8aSRaman Tenneti 				dst_frame_num++;
397*f0687c8aSRaman Tenneti 			}
398*f0687c8aSRaman Tenneti 
399*f0687c8aSRaman Tenneti 			wbflipper.queue_next();
400*f0687c8aSRaman Tenneti 		}
401*f0687c8aSRaman Tenneti 
402*f0687c8aSRaman Tenneti 		if (fds[2].revents) {
403*f0687c8aSRaman Tenneti 			fds[2].revents = 0;
404*f0687c8aSRaman Tenneti 
405*f0687c8aSRaman Tenneti 			card.call_page_flip_handlers();
406*f0687c8aSRaman Tenneti 			wb.Queue();
407*f0687c8aSRaman Tenneti 		}
408*f0687c8aSRaman Tenneti 	}
409*f0687c8aSRaman Tenneti 
410*f0687c8aSRaman Tenneti 	printf("exiting...\n");
411*f0687c8aSRaman Tenneti }
412