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