stereoplay

view src/stereoplay.c @ 0:265a24704ff2

stereoplay
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 06 Mar 2011 20:31:18 +0200
parents
children b50fd6f24975
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 *shmalloc(size_t sz);
33 struct video_file *vf;
34 uint32_t *img;
35 int vid_xsz, vid_ysz, win_xsz, win_ysz;
36 unsigned int tex, sdr;
37 int pfd[2], xsock = -1;
38 int upd_frame;
39 int fullscr;
40 int swap_eyes;
42 Display *dpy;
44 int main(int argc, char **argv)
45 {
46 int pid;
47 char *stereo_combiner, *sdrfile;
49 atexit(cleanup);
51 if(!(vf = vid_open(argv[1]))) {
52 return 1;
53 }
54 vid_xsz = win_xsz = vid_frame_width(vf);
55 vid_ysz = win_ysz = vid_frame_height(vf);
57 if(!(img = shmalloc(vid_frame_size(vf)))) {
58 perror("failed to allocate frame buffer");
59 return 1;
60 }
62 if(pipe(pfd) == -1) {
63 perror("failed to create a self-pipe");
64 return 1;
65 }
67 glutInit(&argc, argv);
68 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
69 glutInitWindowSize(win_xsz, win_ysz);
70 glutCreateWindow(argv[1]);
72 glutDisplayFunc(disp);
73 glutReshapeFunc(reshape);
74 glutKeyboardFunc(keyb);
75 glutSpecialFunc(skeyb);
77 glewInit();
79 /* create the frame texture */
80 glGenTextures(1, &tex);
81 glBindTexture(GL_TEXTURE_2D, tex);
82 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
86 glTexImage2D(GL_TEXTURE_2D, 0, 4, vid_xsz, vid_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
87 glEnable(GL_TEXTURE_2D);
89 if(!(stereo_combiner = getenv("STEREO_METHOD"))) {
90 stereo_combiner = "redcyan";
91 }
93 sdrfile = alloca(strlen(stereo_combiner) + strlen(SDRDIR) + 7);
94 sprintf(sdrfile, SDRDIR "/%s.glsl", stereo_combiner);
96 if(!(sdr = create_program_load(0, sdrfile))) {
97 return 1;
98 }
99 bind_program(sdr);
100 set_uniform_float(sdr, "left_offs", 0.5);
101 set_uniform_float(sdr, "right_offs", 0.0);
103 signal(SIGCHLD, sig);
105 if((pid = fork()) == -1) {
106 perror("failed to fork video decoding process");
107 return 1;
108 } else if(pid) {
109 close(pfd[1]);
110 } else {
111 close(pfd[0]);
112 decoding_loop();
113 _exit(0);
114 }
116 dpy = glXGetCurrentDisplay();
117 xsock = ConnectionNumber(dpy);
119 for(;;) {
120 int res;
121 fd_set rdset;
123 FD_ZERO(&rdset);
124 FD_SET(xsock, &rdset);
125 FD_SET(pfd[0], &rdset);
127 do {
128 res = select((xsock > pfd[0] ? xsock : pfd[0]) + 1, &rdset, 0, 0, 0);
129 } while(res == -1 && errno == EINTR);
131 if(FD_ISSET(pfd[0], &rdset)) {
132 unsigned char done;
133 read(pfd[0], &done, 1);
135 if(done) {
136 exit(0);
137 } else {
138 upd_frame = 1;
139 glutPostRedisplay();
140 }
141 }
143 glutMainLoopEvent();
144 }
146 return 0;
147 }
149 void cleanup(void)
150 {
151 if(tex) {
152 glDeleteTextures(1, &tex);
153 }
154 if(img) {
155 munmap(img, vid_frame_size(vf));
156 }
157 if(vf) {
158 vid_close(vf);
159 }
160 close(pfd[0]);
161 }
163 /* decoding_loop() runs in a separate decoding process and communicates
164 * with the parent process through the pfd[1] pipe.
165 */
166 void decoding_loop(void)
167 {
168 unsigned char done = 0;
169 struct timespec ts;
170 struct timeval tv0, tv;
171 unsigned long frame_nsec = vid_frame_interval(vf) * 1000;
172 printf("nanosecs per frame: %lu\n", frame_nsec);
174 gettimeofday(&tv0, 0);
176 while(vid_get_frame(vf, img) != -1) {
177 write(pfd[1], &done, 1);
179 gettimeofday(&tv, 0);
181 ts.tv_sec = 0;
182 ts.tv_nsec = frame_nsec - (tv.tv_usec - tv0.tv_usec) * 1000;
183 nanosleep(&ts, 0);
185 gettimeofday(&tv0, 0);
186 }
188 done = 1;
189 write(pfd[1], &done, 1);
190 }
192 void disp(void)
193 {
194 if(upd_frame) {
195 /* frame changed, we must re-upload the texture */
196 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_xsz, vid_ysz, GL_BGRA, GL_UNSIGNED_BYTE, img);
197 upd_frame = 0;
198 }
200 glBegin(GL_QUADS);
201 glColor3f(1, 1, 1);
202 glTexCoord2f(0, 1); glVertex2f(-1, -1);
203 glTexCoord2f(1, 1); glVertex2f(1, -1);
204 glTexCoord2f(1, 0); glVertex2f(1, 1);
205 glTexCoord2f(0, 0); glVertex2f(-1, 1);
206 glEnd();
208 glutSwapBuffers();
209 }
211 void reshape(int x, int y)
212 {
213 if(!fullscr) {
214 win_xsz = x;
215 win_ysz = y;
216 }
218 glViewport(0, 0, x, y);
219 }
221 void keyb(unsigned char key, int x, int y)
222 {
223 switch(key) {
224 case 'q':
225 exit(0);
227 case 'f':
228 fullscr = !fullscr;
229 if(fullscr) {
230 glutFullScreen();
231 } else {
232 glutReshapeWindow(win_xsz, win_ysz);
233 }
234 break;
236 case ' ':
237 /* TODO pause/resume */
238 break;
240 case 's':
241 swap_eyes = !swap_eyes;
242 if(swap_eyes) {
243 set_uniform_float(sdr, "left_offs", 0.0);
244 set_uniform_float(sdr, "right_offs", 0.5);
245 } else {
246 set_uniform_float(sdr, "left_offs", 0.5);
247 set_uniform_float(sdr, "right_offs", 0.0);
248 }
249 break;
251 default:
252 break;
253 }
254 }
256 void skeyb(int key, int x, int y)
257 {
258 switch(key) {
259 case GLUT_KEY_LEFT:
260 /* TODO skip fwd */
261 break;
263 case GLUT_KEY_RIGHT:
264 /* TODO skip back */
265 break;
267 case GLUT_KEY_UP:
268 /* TODO skip fwd more */
269 break;
271 case GLUT_KEY_DOWN:
272 /* TODO skip back more */
273 break;
275 case GLUT_KEY_PAGE_UP:
276 /* TODO skip fwd a lot */
277 break;
279 case GLUT_KEY_PAGE_DOWN:
280 /* TODO skip back a lot */
281 break;
283 default:
284 break;
285 }
286 }
288 void sig(int s)
289 {
290 if(s == SIGCHLD) {
291 wait(0);
292 }
293 }
295 void *shmalloc(size_t sz)
296 {
297 int fd;
298 void *shm;
300 if(!(fd = open("/dev/zero", O_RDWR))) {
301 return 0;
302 }
304 if((shm = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
305 shm = 0;
306 }
308 close(fd);
309 return shm;
310 }