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 +}