stereoplay
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/stereoplay.c Sun Mar 06 20:31:18 2011 +0200 1.3 @@ -0,0 +1,310 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <errno.h> 1.8 +#include <signal.h> 1.9 +#include <time.h> 1.10 +#include <assert.h> 1.11 +#include <alloca.h> 1.12 +#include <unistd.h> 1.13 +#include <fcntl.h> 1.14 +#include <sys/mman.h> 1.15 +#include <sys/wait.h> 1.16 +#include <sys/time.h> 1.17 +#include <sys/select.h> 1.18 +#include <X11/Xlib.h> 1.19 +#include <GL/glew.h> 1.20 +#include <GL/glut.h> 1.21 +#include <GL/freeglut_ext.h> 1.22 +#include <GL/glx.h> 1.23 +#include "vid.h" 1.24 +#include "sdr.h" 1.25 +#include "config.h" 1.26 + 1.27 +void cleanup(void); 1.28 +void decoding_loop(void); 1.29 +void disp(void); 1.30 +void reshape(int x, int y); 1.31 +void keyb(unsigned char key, int x, int y); 1.32 +void skeyb(int key, int x, int y); 1.33 +void sig(int s); 1.34 +void *shmalloc(size_t sz); 1.35 + 1.36 +struct video_file *vf; 1.37 +uint32_t *img; 1.38 +int vid_xsz, vid_ysz, win_xsz, win_ysz; 1.39 +unsigned int tex, sdr; 1.40 +int pfd[2], xsock = -1; 1.41 +int upd_frame; 1.42 +int fullscr; 1.43 +int swap_eyes; 1.44 + 1.45 +Display *dpy; 1.46 + 1.47 +int main(int argc, char **argv) 1.48 +{ 1.49 + int pid; 1.50 + char *stereo_combiner, *sdrfile; 1.51 + 1.52 + atexit(cleanup); 1.53 + 1.54 + if(!(vf = vid_open(argv[1]))) { 1.55 + return 1; 1.56 + } 1.57 + vid_xsz = win_xsz = vid_frame_width(vf); 1.58 + vid_ysz = win_ysz = vid_frame_height(vf); 1.59 + 1.60 + if(!(img = shmalloc(vid_frame_size(vf)))) { 1.61 + perror("failed to allocate frame buffer"); 1.62 + return 1; 1.63 + } 1.64 + 1.65 + if(pipe(pfd) == -1) { 1.66 + perror("failed to create a self-pipe"); 1.67 + return 1; 1.68 + } 1.69 + 1.70 + glutInit(&argc, argv); 1.71 + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 1.72 + glutInitWindowSize(win_xsz, win_ysz); 1.73 + glutCreateWindow(argv[1]); 1.74 + 1.75 + glutDisplayFunc(disp); 1.76 + glutReshapeFunc(reshape); 1.77 + glutKeyboardFunc(keyb); 1.78 + glutSpecialFunc(skeyb); 1.79 + 1.80 + glewInit(); 1.81 + 1.82 + /* create the frame texture */ 1.83 + glGenTextures(1, &tex); 1.84 + glBindTexture(GL_TEXTURE_2D, tex); 1.85 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 1.86 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 1.87 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1.88 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.89 + glTexImage2D(GL_TEXTURE_2D, 0, 4, vid_xsz, vid_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 1.90 + glEnable(GL_TEXTURE_2D); 1.91 + 1.92 + if(!(stereo_combiner = getenv("STEREO_METHOD"))) { 1.93 + stereo_combiner = "redcyan"; 1.94 + } 1.95 + 1.96 + sdrfile = alloca(strlen(stereo_combiner) + strlen(SDRDIR) + 7); 1.97 + sprintf(sdrfile, SDRDIR "/%s.glsl", stereo_combiner); 1.98 + 1.99 + if(!(sdr = create_program_load(0, sdrfile))) { 1.100 + return 1; 1.101 + } 1.102 + bind_program(sdr); 1.103 + set_uniform_float(sdr, "left_offs", 0.5); 1.104 + set_uniform_float(sdr, "right_offs", 0.0); 1.105 + 1.106 + signal(SIGCHLD, sig); 1.107 + 1.108 + if((pid = fork()) == -1) { 1.109 + perror("failed to fork video decoding process"); 1.110 + return 1; 1.111 + } else if(pid) { 1.112 + close(pfd[1]); 1.113 + } else { 1.114 + close(pfd[0]); 1.115 + decoding_loop(); 1.116 + _exit(0); 1.117 + } 1.118 + 1.119 + dpy = glXGetCurrentDisplay(); 1.120 + xsock = ConnectionNumber(dpy); 1.121 + 1.122 + for(;;) { 1.123 + int res; 1.124 + fd_set rdset; 1.125 + 1.126 + FD_ZERO(&rdset); 1.127 + FD_SET(xsock, &rdset); 1.128 + FD_SET(pfd[0], &rdset); 1.129 + 1.130 + do { 1.131 + res = select((xsock > pfd[0] ? xsock : pfd[0]) + 1, &rdset, 0, 0, 0); 1.132 + } while(res == -1 && errno == EINTR); 1.133 + 1.134 + if(FD_ISSET(pfd[0], &rdset)) { 1.135 + unsigned char done; 1.136 + read(pfd[0], &done, 1); 1.137 + 1.138 + if(done) { 1.139 + exit(0); 1.140 + } else { 1.141 + upd_frame = 1; 1.142 + glutPostRedisplay(); 1.143 + } 1.144 + } 1.145 + 1.146 + glutMainLoopEvent(); 1.147 + } 1.148 + 1.149 + return 0; 1.150 +} 1.151 + 1.152 +void cleanup(void) 1.153 +{ 1.154 + if(tex) { 1.155 + glDeleteTextures(1, &tex); 1.156 + } 1.157 + if(img) { 1.158 + munmap(img, vid_frame_size(vf)); 1.159 + } 1.160 + if(vf) { 1.161 + vid_close(vf); 1.162 + } 1.163 + close(pfd[0]); 1.164 +} 1.165 + 1.166 +/* decoding_loop() runs in a separate decoding process and communicates 1.167 + * with the parent process through the pfd[1] pipe. 1.168 + */ 1.169 +void decoding_loop(void) 1.170 +{ 1.171 + unsigned char done = 0; 1.172 + struct timespec ts; 1.173 + struct timeval tv0, tv; 1.174 + unsigned long frame_nsec = vid_frame_interval(vf) * 1000; 1.175 + printf("nanosecs per frame: %lu\n", frame_nsec); 1.176 + 1.177 + gettimeofday(&tv0, 0); 1.178 + 1.179 + while(vid_get_frame(vf, img) != -1) { 1.180 + write(pfd[1], &done, 1); 1.181 + 1.182 + gettimeofday(&tv, 0); 1.183 + 1.184 + ts.tv_sec = 0; 1.185 + ts.tv_nsec = frame_nsec - (tv.tv_usec - tv0.tv_usec) * 1000; 1.186 + nanosleep(&ts, 0); 1.187 + 1.188 + gettimeofday(&tv0, 0); 1.189 + } 1.190 + 1.191 + done = 1; 1.192 + write(pfd[1], &done, 1); 1.193 +} 1.194 + 1.195 +void disp(void) 1.196 +{ 1.197 + if(upd_frame) { 1.198 + /* frame changed, we must re-upload the texture */ 1.199 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_xsz, vid_ysz, GL_BGRA, GL_UNSIGNED_BYTE, img); 1.200 + upd_frame = 0; 1.201 + } 1.202 + 1.203 + glBegin(GL_QUADS); 1.204 + glColor3f(1, 1, 1); 1.205 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 1.206 + glTexCoord2f(1, 1); glVertex2f(1, -1); 1.207 + glTexCoord2f(1, 0); glVertex2f(1, 1); 1.208 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 1.209 + glEnd(); 1.210 + 1.211 + glutSwapBuffers(); 1.212 +} 1.213 + 1.214 +void reshape(int x, int y) 1.215 +{ 1.216 + if(!fullscr) { 1.217 + win_xsz = x; 1.218 + win_ysz = y; 1.219 + } 1.220 + 1.221 + glViewport(0, 0, x, y); 1.222 +} 1.223 + 1.224 +void keyb(unsigned char key, int x, int y) 1.225 +{ 1.226 + switch(key) { 1.227 + case 'q': 1.228 + exit(0); 1.229 + 1.230 + case 'f': 1.231 + fullscr = !fullscr; 1.232 + if(fullscr) { 1.233 + glutFullScreen(); 1.234 + } else { 1.235 + glutReshapeWindow(win_xsz, win_ysz); 1.236 + } 1.237 + break; 1.238 + 1.239 + case ' ': 1.240 + /* TODO pause/resume */ 1.241 + break; 1.242 + 1.243 + case 's': 1.244 + swap_eyes = !swap_eyes; 1.245 + if(swap_eyes) { 1.246 + set_uniform_float(sdr, "left_offs", 0.0); 1.247 + set_uniform_float(sdr, "right_offs", 0.5); 1.248 + } else { 1.249 + set_uniform_float(sdr, "left_offs", 0.5); 1.250 + set_uniform_float(sdr, "right_offs", 0.0); 1.251 + } 1.252 + break; 1.253 + 1.254 + default: 1.255 + break; 1.256 + } 1.257 +} 1.258 + 1.259 +void skeyb(int key, int x, int y) 1.260 +{ 1.261 + switch(key) { 1.262 + case GLUT_KEY_LEFT: 1.263 + /* TODO skip fwd */ 1.264 + break; 1.265 + 1.266 + case GLUT_KEY_RIGHT: 1.267 + /* TODO skip back */ 1.268 + break; 1.269 + 1.270 + case GLUT_KEY_UP: 1.271 + /* TODO skip fwd more */ 1.272 + break; 1.273 + 1.274 + case GLUT_KEY_DOWN: 1.275 + /* TODO skip back more */ 1.276 + break; 1.277 + 1.278 + case GLUT_KEY_PAGE_UP: 1.279 + /* TODO skip fwd a lot */ 1.280 + break; 1.281 + 1.282 + case GLUT_KEY_PAGE_DOWN: 1.283 + /* TODO skip back a lot */ 1.284 + break; 1.285 + 1.286 + default: 1.287 + break; 1.288 + } 1.289 +} 1.290 + 1.291 +void sig(int s) 1.292 +{ 1.293 + if(s == SIGCHLD) { 1.294 + wait(0); 1.295 + } 1.296 +} 1.297 + 1.298 +void *shmalloc(size_t sz) 1.299 +{ 1.300 + int fd; 1.301 + void *shm; 1.302 + 1.303 + if(!(fd = open("/dev/zero", O_RDWR))) { 1.304 + return 0; 1.305 + } 1.306 + 1.307 + if((shm = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) { 1.308 + shm = 0; 1.309 + } 1.310 + 1.311 + close(fd); 1.312 + return shm; 1.313 +}