stereoplay

view src/stereoplay.c @ 1:b50fd6f24975

implemented pause
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 06 Mar 2011 20:53:30 +0200
parents 265a24704ff2
children fd671d488cfd
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);
34 struct video_file *vf;
35 uint32_t *img;
36 int vid_xsz, vid_ysz, win_xsz, win_ysz;
37 unsigned int tex, sdr;
38 int decode_pid;
39 int pfd[2], xsock = -1;
40 int upd_frame;
41 int fullscr;
42 int swap_eyes;
44 Display *dpy;
46 int main(int argc, char **argv)
47 {
48 char *stereo_combiner, *sdrfile;
50 atexit(cleanup);
52 if(!(vf = vid_open(argv[1]))) {
53 return 1;
54 }
55 vid_xsz = win_xsz = vid_frame_width(vf);
56 vid_ysz = win_ysz = vid_frame_height(vf);
58 if(!(img = shmalloc(vid_frame_size(vf)))) {
59 perror("failed to allocate frame buffer");
60 return 1;
61 }
63 if(pipe(pfd) == -1) {
64 perror("failed to create a self-pipe");
65 return 1;
66 }
68 glutInit(&argc, argv);
69 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
70 glutInitWindowSize(win_xsz, win_ysz);
71 glutCreateWindow(argv[1]);
73 glutDisplayFunc(disp);
74 glutReshapeFunc(reshape);
75 glutKeyboardFunc(keyb);
76 glutSpecialFunc(skeyb);
78 glewInit();
80 /* create the frame texture */
81 glGenTextures(1, &tex);
82 glBindTexture(GL_TEXTURE_2D, tex);
83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
87 glTexImage2D(GL_TEXTURE_2D, 0, 4, vid_xsz, vid_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
88 glEnable(GL_TEXTURE_2D);
90 if(!(stereo_combiner = getenv("STEREO_METHOD"))) {
91 stereo_combiner = "redcyan";
92 }
94 sdrfile = alloca(strlen(stereo_combiner) + strlen(SDRDIR) + 7);
95 sprintf(sdrfile, SDRDIR "/%s.glsl", stereo_combiner);
97 if(!(sdr = create_program_load(0, sdrfile))) {
98 return 1;
99 }
100 bind_program(sdr);
101 set_uniform_float(sdr, "left_offs", 0.5);
102 set_uniform_float(sdr, "right_offs", 0.0);
104 signal(SIGCHLD, sig);
106 if((decode_pid = fork()) == -1) {
107 perror("failed to fork video decoding process");
108 return 1;
109 } else if(decode_pid) {
110 close(pfd[1]);
111 } else {
112 close(pfd[0]);
113 decoding_loop();
114 _exit(0);
115 }
117 dpy = glXGetCurrentDisplay();
118 xsock = ConnectionNumber(dpy);
120 for(;;) {
121 int res;
122 fd_set rdset;
124 FD_ZERO(&rdset);
125 FD_SET(xsock, &rdset);
126 FD_SET(pfd[0], &rdset);
128 do {
129 res = select((xsock > pfd[0] ? xsock : pfd[0]) + 1, &rdset, 0, 0, 0);
130 } while(res == -1 && errno == EINTR);
132 if(FD_ISSET(pfd[0], &rdset)) {
133 unsigned char done;
134 read(pfd[0], &done, 1);
136 if(done) {
137 exit(0);
138 } else {
139 upd_frame = 1;
140 glutPostRedisplay();
141 }
142 }
144 glutMainLoopEvent();
145 }
147 return 0;
148 }
150 void cleanup(void)
151 {
152 if(tex) {
153 glDeleteTextures(1, &tex);
154 }
155 if(img) {
156 munmap(img, vid_frame_size(vf));
157 }
158 if(vf) {
159 vid_close(vf);
160 }
161 close(pfd[0]);
162 }
164 static int paused;
166 /* decoding_loop() runs in a separate decoding process and communicates
167 * with the parent process through the pfd[1] pipe.
168 */
169 void decoding_loop(void)
170 {
171 unsigned char done = 0;
172 struct timespec ts;
173 struct timeval tv0, tv;
174 unsigned long frame_nsec = vid_frame_interval(vf) * 1000;
175 printf("nanosecs per frame: %lu\n", frame_nsec);
177 signal(SIGUSR1, sig_decode);
179 gettimeofday(&tv0, 0);
181 while(vid_get_frame(vf, img) != -1) {
182 write(pfd[1], &done, 1);
184 gettimeofday(&tv, 0);
186 ts.tv_sec = 0;
187 ts.tv_nsec = frame_nsec - (tv.tv_usec - tv0.tv_usec) * 1000;
188 nanosleep(&ts, 0);
190 while(paused) {
191 pause();
192 }
194 gettimeofday(&tv0, 0);
195 }
197 done = 1;
198 write(pfd[1], &done, 1);
199 }
201 void disp(void)
202 {
203 if(upd_frame) {
204 /* frame changed, we must re-upload the texture */
205 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_xsz, vid_ysz, GL_BGRA, GL_UNSIGNED_BYTE, img);
206 upd_frame = 0;
207 }
209 glBegin(GL_QUADS);
210 glColor3f(1, 1, 1);
211 glTexCoord2f(0, 1); glVertex2f(-1, -1);
212 glTexCoord2f(1, 1); glVertex2f(1, -1);
213 glTexCoord2f(1, 0); glVertex2f(1, 1);
214 glTexCoord2f(0, 0); glVertex2f(-1, 1);
215 glEnd();
217 glutSwapBuffers();
218 }
220 void reshape(int x, int y)
221 {
222 if(!fullscr) {
223 win_xsz = x;
224 win_ysz = y;
225 }
227 glViewport(0, 0, x, y);
228 }
230 void keyb(unsigned char key, int x, int y)
231 {
232 switch(key) {
233 case 'q':
234 exit(0);
236 case 'f':
237 fullscr = !fullscr;
238 if(fullscr) {
239 glutFullScreen();
240 } else {
241 glutReshapeWindow(win_xsz, win_ysz);
242 }
243 break;
245 case ' ':
246 kill(decode_pid, SIGUSR1);
247 break;
249 case 's':
250 swap_eyes = !swap_eyes;
251 if(swap_eyes) {
252 set_uniform_float(sdr, "left_offs", 0.0);
253 set_uniform_float(sdr, "right_offs", 0.5);
254 } else {
255 set_uniform_float(sdr, "left_offs", 0.5);
256 set_uniform_float(sdr, "right_offs", 0.0);
257 }
258 break;
260 default:
261 break;
262 }
263 }
265 void skeyb(int key, int x, int y)
266 {
267 switch(key) {
268 case GLUT_KEY_LEFT:
269 /* TODO skip fwd */
270 break;
272 case GLUT_KEY_RIGHT:
273 /* TODO skip back */
274 break;
276 case GLUT_KEY_UP:
277 /* TODO skip fwd more */
278 break;
280 case GLUT_KEY_DOWN:
281 /* TODO skip back more */
282 break;
284 case GLUT_KEY_PAGE_UP:
285 /* TODO skip fwd a lot */
286 break;
288 case GLUT_KEY_PAGE_DOWN:
289 /* TODO skip back a lot */
290 break;
292 default:
293 break;
294 }
295 }
297 void sig(int s)
298 {
299 if(s == SIGCHLD) {
300 wait(0);
301 }
302 }
304 void sig_decode(int s)
305 {
306 signal(s, sig_decode);
308 if(s == SIGUSR1) {
309 paused = !paused;
310 }
311 }
313 void *shmalloc(size_t sz)
314 {
315 int fd;
316 void *shm;
318 if(!(fd = open("/dev/zero", O_RDWR))) {
319 return 0;
320 }
322 if((shm = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
323 shm = 0;
324 }
326 close(fd);
327 return shm;
328 }