stereoplay

annotate 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
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <string.h>
nuclear@0 4 #include <errno.h>
nuclear@0 5 #include <signal.h>
nuclear@0 6 #include <time.h>
nuclear@0 7 #include <assert.h>
nuclear@0 8 #include <alloca.h>
nuclear@0 9 #include <unistd.h>
nuclear@0 10 #include <fcntl.h>
nuclear@0 11 #include <sys/mman.h>
nuclear@0 12 #include <sys/wait.h>
nuclear@0 13 #include <sys/time.h>
nuclear@0 14 #include <sys/select.h>
nuclear@0 15 #include <X11/Xlib.h>
nuclear@0 16 #include <GL/glew.h>
nuclear@0 17 #include <GL/glut.h>
nuclear@0 18 #include <GL/freeglut_ext.h>
nuclear@0 19 #include <GL/glx.h>
nuclear@0 20 #include "vid.h"
nuclear@0 21 #include "sdr.h"
nuclear@0 22 #include "config.h"
nuclear@0 23
nuclear@0 24 void cleanup(void);
nuclear@0 25 void decoding_loop(void);
nuclear@0 26 void disp(void);
nuclear@0 27 void reshape(int x, int y);
nuclear@0 28 void keyb(unsigned char key, int x, int y);
nuclear@0 29 void skeyb(int key, int x, int y);
nuclear@0 30 void sig(int s);
nuclear@1 31 void sig_decode(int s);
nuclear@0 32 void *shmalloc(size_t sz);
nuclear@0 33
nuclear@0 34 struct video_file *vf;
nuclear@0 35 uint32_t *img;
nuclear@0 36 int vid_xsz, vid_ysz, win_xsz, win_ysz;
nuclear@0 37 unsigned int tex, sdr;
nuclear@1 38 int decode_pid;
nuclear@0 39 int pfd[2], xsock = -1;
nuclear@0 40 int upd_frame;
nuclear@0 41 int fullscr;
nuclear@0 42 int swap_eyes;
nuclear@0 43
nuclear@0 44 Display *dpy;
nuclear@0 45
nuclear@0 46 int main(int argc, char **argv)
nuclear@0 47 {
nuclear@0 48 char *stereo_combiner, *sdrfile;
nuclear@0 49
nuclear@0 50 atexit(cleanup);
nuclear@0 51
nuclear@0 52 if(!(vf = vid_open(argv[1]))) {
nuclear@0 53 return 1;
nuclear@0 54 }
nuclear@0 55 vid_xsz = win_xsz = vid_frame_width(vf);
nuclear@0 56 vid_ysz = win_ysz = vid_frame_height(vf);
nuclear@0 57
nuclear@0 58 if(!(img = shmalloc(vid_frame_size(vf)))) {
nuclear@0 59 perror("failed to allocate frame buffer");
nuclear@0 60 return 1;
nuclear@0 61 }
nuclear@0 62
nuclear@0 63 if(pipe(pfd) == -1) {
nuclear@0 64 perror("failed to create a self-pipe");
nuclear@0 65 return 1;
nuclear@0 66 }
nuclear@0 67
nuclear@0 68 glutInit(&argc, argv);
nuclear@0 69 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
nuclear@0 70 glutInitWindowSize(win_xsz, win_ysz);
nuclear@0 71 glutCreateWindow(argv[1]);
nuclear@0 72
nuclear@0 73 glutDisplayFunc(disp);
nuclear@0 74 glutReshapeFunc(reshape);
nuclear@0 75 glutKeyboardFunc(keyb);
nuclear@0 76 glutSpecialFunc(skeyb);
nuclear@0 77
nuclear@0 78 glewInit();
nuclear@0 79
nuclear@0 80 /* create the frame texture */
nuclear@0 81 glGenTextures(1, &tex);
nuclear@0 82 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@0 83 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
nuclear@0 84 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
nuclear@0 85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 87 glTexImage2D(GL_TEXTURE_2D, 0, 4, vid_xsz, vid_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@0 88 glEnable(GL_TEXTURE_2D);
nuclear@0 89
nuclear@0 90 if(!(stereo_combiner = getenv("STEREO_METHOD"))) {
nuclear@0 91 stereo_combiner = "redcyan";
nuclear@0 92 }
nuclear@0 93
nuclear@0 94 sdrfile = alloca(strlen(stereo_combiner) + strlen(SDRDIR) + 7);
nuclear@0 95 sprintf(sdrfile, SDRDIR "/%s.glsl", stereo_combiner);
nuclear@0 96
nuclear@0 97 if(!(sdr = create_program_load(0, sdrfile))) {
nuclear@0 98 return 1;
nuclear@0 99 }
nuclear@0 100 bind_program(sdr);
nuclear@0 101 set_uniform_float(sdr, "left_offs", 0.5);
nuclear@0 102 set_uniform_float(sdr, "right_offs", 0.0);
nuclear@0 103
nuclear@0 104 signal(SIGCHLD, sig);
nuclear@0 105
nuclear@1 106 if((decode_pid = fork()) == -1) {
nuclear@0 107 perror("failed to fork video decoding process");
nuclear@0 108 return 1;
nuclear@1 109 } else if(decode_pid) {
nuclear@0 110 close(pfd[1]);
nuclear@0 111 } else {
nuclear@0 112 close(pfd[0]);
nuclear@0 113 decoding_loop();
nuclear@0 114 _exit(0);
nuclear@0 115 }
nuclear@0 116
nuclear@0 117 dpy = glXGetCurrentDisplay();
nuclear@0 118 xsock = ConnectionNumber(dpy);
nuclear@0 119
nuclear@0 120 for(;;) {
nuclear@0 121 int res;
nuclear@0 122 fd_set rdset;
nuclear@0 123
nuclear@0 124 FD_ZERO(&rdset);
nuclear@0 125 FD_SET(xsock, &rdset);
nuclear@0 126 FD_SET(pfd[0], &rdset);
nuclear@0 127
nuclear@0 128 do {
nuclear@0 129 res = select((xsock > pfd[0] ? xsock : pfd[0]) + 1, &rdset, 0, 0, 0);
nuclear@0 130 } while(res == -1 && errno == EINTR);
nuclear@0 131
nuclear@0 132 if(FD_ISSET(pfd[0], &rdset)) {
nuclear@0 133 unsigned char done;
nuclear@0 134 read(pfd[0], &done, 1);
nuclear@0 135
nuclear@0 136 if(done) {
nuclear@0 137 exit(0);
nuclear@0 138 } else {
nuclear@0 139 upd_frame = 1;
nuclear@0 140 glutPostRedisplay();
nuclear@0 141 }
nuclear@0 142 }
nuclear@0 143
nuclear@0 144 glutMainLoopEvent();
nuclear@0 145 }
nuclear@0 146
nuclear@0 147 return 0;
nuclear@0 148 }
nuclear@0 149
nuclear@0 150 void cleanup(void)
nuclear@0 151 {
nuclear@0 152 if(tex) {
nuclear@0 153 glDeleteTextures(1, &tex);
nuclear@0 154 }
nuclear@0 155 if(img) {
nuclear@0 156 munmap(img, vid_frame_size(vf));
nuclear@0 157 }
nuclear@0 158 if(vf) {
nuclear@0 159 vid_close(vf);
nuclear@0 160 }
nuclear@0 161 close(pfd[0]);
nuclear@0 162 }
nuclear@0 163
nuclear@1 164 static int paused;
nuclear@1 165
nuclear@0 166 /* decoding_loop() runs in a separate decoding process and communicates
nuclear@0 167 * with the parent process through the pfd[1] pipe.
nuclear@0 168 */
nuclear@0 169 void decoding_loop(void)
nuclear@0 170 {
nuclear@0 171 unsigned char done = 0;
nuclear@0 172 struct timespec ts;
nuclear@0 173 struct timeval tv0, tv;
nuclear@0 174 unsigned long frame_nsec = vid_frame_interval(vf) * 1000;
nuclear@0 175 printf("nanosecs per frame: %lu\n", frame_nsec);
nuclear@0 176
nuclear@1 177 signal(SIGUSR1, sig_decode);
nuclear@1 178
nuclear@0 179 gettimeofday(&tv0, 0);
nuclear@0 180
nuclear@0 181 while(vid_get_frame(vf, img) != -1) {
nuclear@0 182 write(pfd[1], &done, 1);
nuclear@0 183
nuclear@0 184 gettimeofday(&tv, 0);
nuclear@0 185
nuclear@0 186 ts.tv_sec = 0;
nuclear@0 187 ts.tv_nsec = frame_nsec - (tv.tv_usec - tv0.tv_usec) * 1000;
nuclear@0 188 nanosleep(&ts, 0);
nuclear@0 189
nuclear@1 190 while(paused) {
nuclear@1 191 pause();
nuclear@1 192 }
nuclear@1 193
nuclear@0 194 gettimeofday(&tv0, 0);
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 done = 1;
nuclear@0 198 write(pfd[1], &done, 1);
nuclear@0 199 }
nuclear@0 200
nuclear@0 201 void disp(void)
nuclear@0 202 {
nuclear@0 203 if(upd_frame) {
nuclear@0 204 /* frame changed, we must re-upload the texture */
nuclear@0 205 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_xsz, vid_ysz, GL_BGRA, GL_UNSIGNED_BYTE, img);
nuclear@0 206 upd_frame = 0;
nuclear@0 207 }
nuclear@0 208
nuclear@0 209 glBegin(GL_QUADS);
nuclear@0 210 glColor3f(1, 1, 1);
nuclear@0 211 glTexCoord2f(0, 1); glVertex2f(-1, -1);
nuclear@0 212 glTexCoord2f(1, 1); glVertex2f(1, -1);
nuclear@0 213 glTexCoord2f(1, 0); glVertex2f(1, 1);
nuclear@0 214 glTexCoord2f(0, 0); glVertex2f(-1, 1);
nuclear@0 215 glEnd();
nuclear@0 216
nuclear@0 217 glutSwapBuffers();
nuclear@0 218 }
nuclear@0 219
nuclear@0 220 void reshape(int x, int y)
nuclear@0 221 {
nuclear@0 222 if(!fullscr) {
nuclear@0 223 win_xsz = x;
nuclear@0 224 win_ysz = y;
nuclear@0 225 }
nuclear@0 226
nuclear@0 227 glViewport(0, 0, x, y);
nuclear@0 228 }
nuclear@0 229
nuclear@0 230 void keyb(unsigned char key, int x, int y)
nuclear@0 231 {
nuclear@0 232 switch(key) {
nuclear@0 233 case 'q':
nuclear@0 234 exit(0);
nuclear@0 235
nuclear@0 236 case 'f':
nuclear@0 237 fullscr = !fullscr;
nuclear@0 238 if(fullscr) {
nuclear@0 239 glutFullScreen();
nuclear@0 240 } else {
nuclear@0 241 glutReshapeWindow(win_xsz, win_ysz);
nuclear@0 242 }
nuclear@0 243 break;
nuclear@0 244
nuclear@0 245 case ' ':
nuclear@1 246 kill(decode_pid, SIGUSR1);
nuclear@0 247 break;
nuclear@0 248
nuclear@0 249 case 's':
nuclear@0 250 swap_eyes = !swap_eyes;
nuclear@0 251 if(swap_eyes) {
nuclear@0 252 set_uniform_float(sdr, "left_offs", 0.0);
nuclear@0 253 set_uniform_float(sdr, "right_offs", 0.5);
nuclear@0 254 } else {
nuclear@0 255 set_uniform_float(sdr, "left_offs", 0.5);
nuclear@0 256 set_uniform_float(sdr, "right_offs", 0.0);
nuclear@0 257 }
nuclear@0 258 break;
nuclear@0 259
nuclear@0 260 default:
nuclear@0 261 break;
nuclear@0 262 }
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 void skeyb(int key, int x, int y)
nuclear@0 266 {
nuclear@0 267 switch(key) {
nuclear@0 268 case GLUT_KEY_LEFT:
nuclear@0 269 /* TODO skip fwd */
nuclear@0 270 break;
nuclear@0 271
nuclear@0 272 case GLUT_KEY_RIGHT:
nuclear@0 273 /* TODO skip back */
nuclear@0 274 break;
nuclear@0 275
nuclear@0 276 case GLUT_KEY_UP:
nuclear@0 277 /* TODO skip fwd more */
nuclear@0 278 break;
nuclear@0 279
nuclear@0 280 case GLUT_KEY_DOWN:
nuclear@0 281 /* TODO skip back more */
nuclear@0 282 break;
nuclear@0 283
nuclear@0 284 case GLUT_KEY_PAGE_UP:
nuclear@0 285 /* TODO skip fwd a lot */
nuclear@0 286 break;
nuclear@0 287
nuclear@0 288 case GLUT_KEY_PAGE_DOWN:
nuclear@0 289 /* TODO skip back a lot */
nuclear@0 290 break;
nuclear@0 291
nuclear@0 292 default:
nuclear@0 293 break;
nuclear@0 294 }
nuclear@0 295 }
nuclear@0 296
nuclear@0 297 void sig(int s)
nuclear@0 298 {
nuclear@0 299 if(s == SIGCHLD) {
nuclear@0 300 wait(0);
nuclear@0 301 }
nuclear@0 302 }
nuclear@0 303
nuclear@1 304 void sig_decode(int s)
nuclear@1 305 {
nuclear@1 306 signal(s, sig_decode);
nuclear@1 307
nuclear@1 308 if(s == SIGUSR1) {
nuclear@1 309 paused = !paused;
nuclear@1 310 }
nuclear@1 311 }
nuclear@1 312
nuclear@0 313 void *shmalloc(size_t sz)
nuclear@0 314 {
nuclear@0 315 int fd;
nuclear@0 316 void *shm;
nuclear@0 317
nuclear@0 318 if(!(fd = open("/dev/zero", O_RDWR))) {
nuclear@0 319 return 0;
nuclear@0 320 }
nuclear@0 321
nuclear@0 322 if((shm = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
nuclear@0 323 shm = 0;
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 close(fd);
nuclear@0 327 return shm;
nuclear@0 328 }