stereoplay

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