stereoplay

view src/stereoplay.c @ 2:fd671d488cfd

cleanup of the hacks
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 03 Nov 2011 21:45:59 +0200
parents b50fd6f24975
children acf3d25f23cb
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <signal.h>
6 #include <time.h>
7 #include <assert.h>
8 #include <alloca.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <sys/mman.h>
12 #include <sys/wait.h>
13 #include <sys/time.h>
14 #include <sys/select.h>
15 #include <X11/Xlib.h>
16 #include <GL/glew.h>
17 #include <GL/glut.h>
18 #include <GL/freeglut_ext.h>
19 #include <GL/glx.h>
20 #include "vid.h"
21 #include "sdr.h"
22 #include "config.h"
24 void cleanup(void);
25 void decoding_loop(void);
26 void disp(void);
27 void reshape(int x, int y);
28 void keyb(unsigned char key, int x, int y);
29 void skeyb(int key, int x, int y);
30 void sig(int s);
31 void sig_decode(int s);
32 void *shmalloc(size_t sz);
33 int parse_args(int argc, char **argv);
35 struct video_file *vf;
36 uint32_t *img;
37 int vid_xsz, vid_ysz, win_xsz, win_ysz;
38 unsigned int tex, sdr;
39 int decode_pid;
40 int pfd[2], xsock = -1;
41 int upd_frame;
42 int fullscr;
43 int swap_eyes;
45 Display *dpy;
47 const char *vid_fname;
48 int busy_loop;
51 int main(int argc, char **argv)
52 {
53 struct timeval *selwait = 0;
54 /*char *stereo_combiner, *sdrfile;*/
56 if(parse_args(argc, argv) == -1) {
57 return 1;
58 }
60 atexit(cleanup);
62 if(!(vf = vid_open(vid_fname))) {
63 return 1;
64 }
65 vid_xsz = win_xsz = vid_frame_width(vf);
66 vid_ysz = win_ysz = vid_frame_height(vf);
68 if(!(img = shmalloc(vid_frame_size(vf)))) {
69 perror("failed to allocate frame buffer");
70 return 1;
71 }
73 if(pipe(pfd) == -1) {
74 perror("failed to create a self-pipe");
75 return 1;
76 }
78 glutInit(&argc, argv);
79 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_STEREO);
80 glutInitWindowSize(win_xsz, win_ysz);
81 glutCreateWindow(argv[1]);
83 glutDisplayFunc(disp);
84 glutReshapeFunc(reshape);
85 glutKeyboardFunc(keyb);
86 glutSpecialFunc(skeyb);
88 if(busy_loop) {
89 selwait = alloca(sizeof *selwait);
90 selwait->tv_sec = selwait->tv_usec = 0;
91 }
93 glewInit();
95 /* create the frame texture */
96 glGenTextures(1, &tex);
97 glBindTexture(GL_TEXTURE_2D, tex);
98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
101 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
102 glTexImage2D(GL_TEXTURE_2D, 0, 4, vid_xsz, vid_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
103 glEnable(GL_TEXTURE_2D);
105 /*if(!(stereo_combiner = getenv("STEREO_METHOD"))) {
106 stereo_combiner = "redcyan";
107 }
109 sdrfile = alloca(strlen(stereo_combiner) + strlen(SDRDIR) + 7);
110 sprintf(sdrfile, SDRDIR "/%s.glsl", stereo_combiner);
112 if(!(sdr = create_program_load(0, sdrfile))) {
113 return 1;
114 }
115 bind_program(sdr);
116 set_uniform_float(sdr, "left_offs", 0.5);
117 set_uniform_float(sdr, "right_offs", 0.0);*/
119 signal(SIGCHLD, sig);
121 if((decode_pid = fork()) == -1) {
122 perror("failed to fork video decoding process");
123 return 1;
124 } else if(decode_pid) {
125 close(pfd[1]);
126 } else {
127 close(pfd[0]);
128 decoding_loop();
129 _exit(0);
130 }
132 dpy = glXGetCurrentDisplay();
133 xsock = ConnectionNumber(dpy);
135 for(;;) {
136 int res;
137 fd_set rdset;
139 FD_ZERO(&rdset);
140 FD_SET(xsock, &rdset);
141 FD_SET(pfd[0], &rdset);
143 do {
144 res = select((xsock > pfd[0] ? xsock : pfd[0]) + 1, &rdset, 0, 0, selwait);
145 } while(res == -1 && errno == EINTR);
147 if(FD_ISSET(pfd[0], &rdset)) {
148 unsigned char done;
149 read(pfd[0], &done, 1);
151 if(done) {
152 exit(0);
153 } else {
154 upd_frame = 1;
155 glutPostRedisplay();
156 }
157 }
159 glutMainLoopEvent();
160 if(busy_loop) {
161 glutPostRedisplay();
162 }
163 }
165 return 0;
166 }
168 void cleanup(void)
169 {
170 if(tex) {
171 glDeleteTextures(1, &tex);
172 }
173 if(img) {
174 munmap(img, vid_frame_size(vf));
175 }
176 if(vf) {
177 vid_close(vf);
178 }
179 close(pfd[0]);
180 }
183 static int paused;
185 /* decoding_loop() runs in a separate decoding process and communicates
186 * with the parent process through the pfd[1] pipe.
187 */
188 void decoding_loop(void)
189 {
190 unsigned char done = 0;
191 struct timespec ts;
192 struct timeval tv0, tv;
193 unsigned long frame_nsec = vid_frame_interval(vf) * 1000;
194 printf("nanosecs per frame: %lu\n", frame_nsec);
196 signal(SIGUSR1, sig_decode);
198 gettimeofday(&tv0, 0);
200 while(vid_get_frame(vf, img) != -1) {
201 write(pfd[1], &done, 1);
203 gettimeofday(&tv, 0);
205 ts.tv_sec = 0;
206 ts.tv_nsec = frame_nsec - (tv.tv_usec - tv0.tv_usec) * 1000;
207 nanosleep(&ts, 0);
209 while(paused) {
210 pause();
211 }
213 gettimeofday(&tv0, 0);
214 }
216 done = 1;
217 write(pfd[1], &done, 1);
218 }
220 void disp(void)
221 {
222 if(upd_frame) {
223 /* frame changed, we must re-upload the texture */
224 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_xsz, vid_ysz, GL_BGRA, GL_UNSIGNED_BYTE, img);
225 upd_frame = 0;
226 }
228 glDrawBuffer(swap_eyes ? GL_BACK_RIGHT : GL_BACK_LEFT);
230 glBegin(GL_QUADS);
231 glColor3f(1, 1, 1);
232 glTexCoord2f(0, 1); glVertex2f(-1, -1);
233 glTexCoord2f(0.5, 1); glVertex2f(1, -1);
234 glTexCoord2f(0.5, 0); glVertex2f(1, 1);
235 glTexCoord2f(0, 0); glVertex2f(-1, 1);
236 glEnd();
238 glDrawBuffer(swap_eyes ? GL_BACK_LEFT : GL_BACK_RIGHT);
240 glBegin(GL_QUADS);
241 glColor3f(1, 1, 1);
242 glTexCoord2f(0.5, 1); glVertex2f(-1, -1);
243 glTexCoord2f(1, 1); glVertex2f(1, -1);
244 glTexCoord2f(1, 0); glVertex2f(1, 1);
245 glTexCoord2f(0.5, 0); glVertex2f(-1, 1);
246 glEnd();
248 glutSwapBuffers();
249 }
251 void reshape(int x, int y)
252 {
253 if(!fullscr) {
254 win_xsz = x;
255 win_ysz = y;
256 }
258 glViewport(0, 0, x, y);
259 }
261 void keyb(unsigned char key, int x, int y)
262 {
263 switch(key) {
264 case 'q':
265 exit(0);
267 case 'f':
268 fullscr = !fullscr;
269 if(fullscr) {
270 glutFullScreen();
271 } else {
272 glutReshapeWindow(win_xsz, win_ysz);
273 }
274 break;
276 case ' ':
277 kill(decode_pid, SIGUSR1);
278 break;
280 case 's':
281 swap_eyes = !swap_eyes;
282 /*if(swap_eyes) {
283 set_uniform_float(sdr, "left_offs", 0.0);
284 set_uniform_float(sdr, "right_offs", 0.5);
285 } else {
286 set_uniform_float(sdr, "left_offs", 0.5);
287 set_uniform_float(sdr, "right_offs", 0.0);
288 }*/
289 break;
291 default:
292 break;
293 }
294 }
296 void skeyb(int key, int x, int y)
297 {
298 switch(key) {
299 case GLUT_KEY_LEFT:
300 /* TODO skip fwd */
301 break;
303 case GLUT_KEY_RIGHT:
304 /* TODO skip back */
305 break;
307 case GLUT_KEY_UP:
308 /* TODO skip fwd more */
309 break;
311 case GLUT_KEY_DOWN:
312 /* TODO skip back more */
313 break;
315 case GLUT_KEY_PAGE_UP:
316 /* TODO skip fwd a lot */
317 break;
319 case GLUT_KEY_PAGE_DOWN:
320 /* TODO skip back a lot */
321 break;
323 default:
324 break;
325 }
326 }
328 void sig(int s)
329 {
330 if(s == SIGCHLD) {
331 wait(0);
332 }
333 }
335 void sig_decode(int s)
336 {
337 signal(s, sig_decode);
339 if(s == SIGUSR1) {
340 paused = !paused;
341 }
342 }
344 void *shmalloc(size_t sz)
345 {
346 int fd;
347 void *shm;
349 if(!(fd = open("/dev/zero", O_RDWR))) {
350 return 0;
351 }
353 if((shm = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
354 shm = 0;
355 }
357 close(fd);
358 return shm;
359 }
361 int parse_args(int argc, char **argv)
362 {
363 int i;
364 char *method = 0;
366 for(i=1; i<argc; i++) {
367 if(argv[i][0] == '-' && argv[i][2] == 0) {
368 switch(argv[i][1]) {
369 case 'b':
370 busy_loop = 1;
371 printf("busy looping!\n");
372 break;
374 case 's':
375 method = argv[++i];
376 break;
378 case 'h':
379 printf("Usage: %s [options]\n", argv[0]);
380 printf("options:\n");
381 printf(" -b busy loop (redraw continuously)\n");
382 printf(" -s <method> stereo presentation method\n");
383 printf(" -h print usage and exit\n");
384 return 0;
386 default:
387 fprintf(stderr, "invalid option: %s\n", argv[i]);
388 return -1;
389 }
390 } else {
391 if(vid_fname) {
392 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
393 return -1;
394 }
395 vid_fname = argv[i];
396 }
397 }
399 if(!vid_fname) {
400 fprintf(stderr, "you must specify a video file to open\n");
401 return -1;
402 }
404 return 0;
405 }