stereoplay

changeset 0:265a24704ff2

stereoplay
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 06 Mar 2011 20:31:18 +0200
parents
children b50fd6f24975
files Makefile sdr/colorcode.glsl sdr/redblue.glsl sdr/redcyan.glsl src/config.h src/sdr.c src/sdr.h src/stereoplay.c src/vid.c src/vid.h
diffstat 10 files changed, 928 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Sun Mar 06 20:31:18 2011 +0200
     1.3 @@ -0,0 +1,32 @@
     1.4 +PREFIX = /usr/local
     1.5 +sdrdir = $(PREFIX)/share/stereoplay
     1.6 +sdr = $(wildcard sdr/*.glsl)
     1.7 +
     1.8 +src = $(wildcard src/*.c)
     1.9 +obj = $(src:.c=.o)
    1.10 +bin = stereoplay
    1.11 +
    1.12 +CC = gcc
    1.13 +CFLAGS = -pedantic -Wall -g
    1.14 +LDFLAGS = $(gllibs_$(shell uname -s)) -lavformat -lavcodec -lswscale
    1.15 +
    1.16 +gllibs_Linux = -lGL -lGLU -lglut -lGLEW
    1.17 +
    1.18 +$(bin): $(obj)
    1.19 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    1.20 +
    1.21 +.PHONY: clean
    1.22 +clean:
    1.23 +	rm -f $(obj) $(bin)
    1.24 +
    1.25 +.PHONY: install
    1.26 +install:
    1.27 +	install -m 775 $(bin) $(PREFIX)/bin/$(bin)
    1.28 +	install -d $(sdrdir)
    1.29 +	install -m 664 $(sdr) $(sdrdir)/
    1.30 +
    1.31 +.PHONY: uninstall
    1.32 +uninstall:
    1.33 +	rm -f $(PREFIX)/bin/$(bin)
    1.34 +	rm -f $(sdrdir)/*
    1.35 +	rmdir $(sdrdir)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/sdr/colorcode.glsl	Sun Mar 06 20:31:18 2011 +0200
     2.3 @@ -0,0 +1,19 @@
     2.4 +uniform sampler2D tex;
     2.5 +uniform float left_offs, right_offs;
     2.6 +
     2.7 +void main()
     2.8 +{
     2.9 +	vec2 tc_half = gl_TexCoord[0].st * vec2(0.5, 1.0);
    2.10 +	vec2 tc_left = tc_half + vec2(left_offs, 0.0);
    2.11 +	vec2 tc_right = tc_half + vec2(right_offs, 0.0);
    2.12 +	
    2.13 +	vec3 left = texture2D(tex, tc_left).rgb;
    2.14 +	vec3 right = texture2D(tex, tc_right).rgb;
    2.15 +
    2.16 +	vec3 col, coeff = vec3(0.15, 0.15, 0.7);
    2.17 +	col.r = left.r;
    2.18 +	col.g = left.g;
    2.19 +	col.b = dot(right, coeff);
    2.20 +
    2.21 +	gl_FragColor = vec4(col, 1.0);
    2.22 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/sdr/redblue.glsl	Sun Mar 06 20:31:18 2011 +0200
     3.3 @@ -0,0 +1,21 @@
     3.4 +uniform sampler2D tex;
     3.5 +uniform float left_offs, right_offs;
     3.6 +
     3.7 +void main()
     3.8 +{
     3.9 +	vec2 tc_half = gl_TexCoord[0].st * vec2(0.5, 1.0);
    3.10 +	vec2 tc_left = tc_half + vec2(left_offs, 0.0);
    3.11 +	vec2 tc_right = tc_half + vec2(right_offs, 0.0);
    3.12 +	
    3.13 +	vec3 left = texture2D(tex, tc_left).rgb;
    3.14 +	vec3 right = texture2D(tex, tc_right).rgb;
    3.15 +
    3.16 +
    3.17 +
    3.18 +	vec3 col;
    3.19 +	col.r = (left.r + left.g + left.b) / 3.0;
    3.20 +	col.g = 0.0;
    3.21 +	col.b = (right.r + right.g + right.b) / 3.0;
    3.22 +
    3.23 +	gl_FragColor = vec4(col, 1.0);
    3.24 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/sdr/redcyan.glsl	Sun Mar 06 20:31:18 2011 +0200
     4.3 @@ -0,0 +1,19 @@
     4.4 +uniform sampler2D tex;
     4.5 +uniform float left_offs, right_offs;
     4.6 +
     4.7 +void main()
     4.8 +{
     4.9 +	vec2 tc_half = gl_TexCoord[0].st * vec2(0.5, 1.0);
    4.10 +	vec2 tc_left = tc_half + vec2(left_offs, 0.0);
    4.11 +	vec2 tc_right = tc_half + vec2(right_offs, 0.0);
    4.12 +	
    4.13 +	vec3 left = texture2D(tex, tc_left).rgb;
    4.14 +	vec3 right = texture2D(tex, tc_right).rgb;
    4.15 +
    4.16 +	vec3 col;
    4.17 +	col.r = left.r;
    4.18 +	col.g = right.g;
    4.19 +	col.b = right.b;
    4.20 +
    4.21 +	gl_FragColor = vec4(col, 1.0);
    4.22 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/config.h	Sun Mar 06 20:31:18 2011 +0200
     5.3 @@ -0,0 +1,7 @@
     5.4 +#ifndef CONFIG_H_
     5.5 +#define CONFIG_H_
     5.6 +
     5.7 +#define PREFIX	"/usr/local"
     5.8 +#define SDRDIR	PREFIX "/share/stereoplay"
     5.9 +
    5.10 +#endif	/* CONFIG_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/sdr.c	Sun Mar 06 20:31:18 2011 +0200
     6.3 @@ -0,0 +1,299 @@
     6.4 +#include <stdio.h>
     6.5 +#include <stdlib.h>
     6.6 +#include <string.h>
     6.7 +#include <errno.h>
     6.8 +#include <assert.h>
     6.9 +#include <GL/glew.h>
    6.10 +
    6.11 +#if defined(unix) || defined(__unix__) || defined(__APPLE__)
    6.12 +#include <unistd.h>
    6.13 +#include <sys/stat.h>
    6.14 +#endif	/* unix */
    6.15 +
    6.16 +#include "sdr.h"
    6.17 +
    6.18 +unsigned int create_vertex_shader(const char *src)
    6.19 +{
    6.20 +	return create_shader(src, GL_VERTEX_SHADER);
    6.21 +}
    6.22 +
    6.23 +unsigned int create_pixel_shader(const char *src)
    6.24 +{
    6.25 +	return create_shader(src, GL_FRAGMENT_SHADER);
    6.26 +}
    6.27 +
    6.28 +unsigned int create_shader(const char *src, unsigned int sdr_type)
    6.29 +{
    6.30 +	unsigned int sdr;
    6.31 +	int success, info_len;
    6.32 +	char *info_str = 0;
    6.33 +	GLenum err;
    6.34 +
    6.35 +	sdr = glCreateShader(sdr_type);
    6.36 +	assert(glGetError() == GL_NO_ERROR);
    6.37 +	glShaderSource(sdr, 1, &src, 0);
    6.38 +	err = glGetError();
    6.39 +	assert(err == GL_NO_ERROR);
    6.40 +	glCompileShader(sdr);
    6.41 +	assert(glGetError() == GL_NO_ERROR);
    6.42 +
    6.43 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
    6.44 +	assert(glGetError() == GL_NO_ERROR);
    6.45 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
    6.46 +	assert(glGetError() == GL_NO_ERROR);
    6.47 +
    6.48 +	if(info_len) {
    6.49 +		if((info_str = malloc(info_len + 1))) {
    6.50 +			glGetShaderInfoLog(sdr, info_len, 0, info_str);
    6.51 +			assert(glGetError() == GL_NO_ERROR);
    6.52 +		}
    6.53 +	}
    6.54 +
    6.55 +	if(success) {
    6.56 +		fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
    6.57 +	} else {
    6.58 +		fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
    6.59 +		glDeleteShader(sdr);
    6.60 +		sdr = 0;
    6.61 +	}
    6.62 +
    6.63 +	free(info_str);
    6.64 +	return sdr;
    6.65 +}
    6.66 +
    6.67 +void free_shader(unsigned int sdr)
    6.68 +{
    6.69 +	glDeleteShader(sdr);
    6.70 +}
    6.71 +
    6.72 +unsigned int load_vertex_shader(const char *fname)
    6.73 +{
    6.74 +	return load_shader(fname, GL_VERTEX_SHADER);
    6.75 +}
    6.76 +
    6.77 +unsigned int load_pixel_shader(const char *fname)
    6.78 +{
    6.79 +	return load_shader(fname, GL_FRAGMENT_SHADER);
    6.80 +}
    6.81 +
    6.82 +unsigned int load_shader(const char *fname, unsigned int sdr_type)
    6.83 +{
    6.84 +#if defined(unix) || defined(__unix__)
    6.85 +	struct stat st;
    6.86 +#endif
    6.87 +	unsigned int sdr;
    6.88 +	size_t filesize;
    6.89 +	FILE *fp;
    6.90 +	char *src;
    6.91 +
    6.92 +	if(!(fp = fopen(fname, "r"))) {
    6.93 +		fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
    6.94 +		return 0;
    6.95 +	}
    6.96 +
    6.97 +#if defined(unix) || defined(__unix__) || defined(__APPLE__)
    6.98 +	fstat(fileno(fp), &st);
    6.99 +	filesize = st.st_size;
   6.100 +#else
   6.101 +	fseek(fp, 0, SEEK_END);
   6.102 +	filesize = ftell(fp);
   6.103 +	fseek(fp, 0, SEEK_SET);
   6.104 +#endif	/* unix */
   6.105 +
   6.106 +	if(!(src = malloc(filesize + 1))) {
   6.107 +		fclose(fp);
   6.108 +		return 0;
   6.109 +	}
   6.110 +	fread(src, 1, filesize, fp);
   6.111 +	src[filesize] = 0;
   6.112 +	fclose(fp);
   6.113 +
   6.114 +	fprintf(stderr, "compiling %s shader: %s... ", (sdr_type == GL_VERTEX_SHADER ? "vertex" : "pixel"), fname);
   6.115 +	sdr = create_shader(src, sdr_type);
   6.116 +
   6.117 +	free(src);
   6.118 +	return sdr;
   6.119 +}
   6.120 +
   6.121 +
   6.122 +unsigned int get_vertex_shader(const char *fname)
   6.123 +{
   6.124 +	return get_shader(fname, GL_VERTEX_SHADER);
   6.125 +}
   6.126 +
   6.127 +unsigned int get_pixel_shader(const char *fname)
   6.128 +{
   6.129 +	return get_shader(fname, GL_FRAGMENT_SHADER);
   6.130 +}
   6.131 +
   6.132 +unsigned int get_shader(const char *fname, unsigned int sdr_type)
   6.133 +{
   6.134 +	unsigned int sdr;
   6.135 +#if 0
   6.136 +	if((res = get_resource(sdrman, fname))) {
   6.137 +		/* TODO: validate that the shader matches sdr_type? */
   6.138 +		return (uintptr_t)res;
   6.139 +	}
   6.140 +#endif
   6.141 +
   6.142 +	if(!(sdr = load_shader(fname, sdr_type))) {
   6.143 +		return 0;
   6.144 +	}
   6.145 +	add_shader(fname, sdr);
   6.146 +	return sdr;
   6.147 +}
   6.148 +
   6.149 +int add_shader(const char *fname, unsigned int sdr)
   6.150 +{
   6.151 +	return 0;/*add_resource(sdrman, fname, (void*)(uintptr_t)sdr);*/
   6.152 +}
   6.153 +
   6.154 +int remove_shader(const char *fname)
   6.155 +{
   6.156 +	return 0;/*remove_resource(sdrman, fname);*/
   6.157 +}
   6.158 +
   6.159 +
   6.160 +/* ---- gpu programs ---- */
   6.161 +
   6.162 +unsigned int create_program(void)
   6.163 +{
   6.164 +	unsigned int prog = glCreateProgram();
   6.165 +	assert(glGetError() == GL_NO_ERROR);
   6.166 +	return prog;
   6.167 +}
   6.168 +
   6.169 +unsigned int create_program_link(unsigned int vs, unsigned int ps)
   6.170 +{
   6.171 +	unsigned int prog;
   6.172 +	if(!vs && !ps) {
   6.173 +		return 0;
   6.174 +	}
   6.175 +
   6.176 +	if(!(prog = create_program())) {
   6.177 +		return 0;
   6.178 +	}
   6.179 +	
   6.180 +	if(vs) {
   6.181 +		attach_shader(prog, vs);
   6.182 +		assert(glGetError() == GL_NO_ERROR);
   6.183 +	}
   6.184 +	if(ps) {
   6.185 +		attach_shader(prog, ps);
   6.186 +		assert(glGetError() == GL_NO_ERROR);
   6.187 +	}
   6.188 +	
   6.189 +	if(link_program(prog) == -1) {
   6.190 +		free_program(prog);
   6.191 +		return 0;
   6.192 +	}
   6.193 +	return prog;
   6.194 +}
   6.195 +
   6.196 +unsigned int create_program_load(const char *vfile, const char *pfile)
   6.197 +{
   6.198 +	unsigned int vs = 0, ps = 0;
   6.199 +
   6.200 +	if(vfile) {
   6.201 +		if(!(vs = get_vertex_shader(vfile))) {
   6.202 +			return 0;
   6.203 +		}
   6.204 +	}
   6.205 +	if(pfile) {
   6.206 +		if(!(ps = get_pixel_shader(pfile))) {
   6.207 +			return 0;
   6.208 +		}
   6.209 +	}
   6.210 +	return create_program_link(vs, ps);
   6.211 +}
   6.212 +
   6.213 +void free_program(unsigned int sdr)
   6.214 +{
   6.215 +	glDeleteProgram(sdr);
   6.216 +}
   6.217 +
   6.218 +void attach_shader(unsigned int prog, unsigned int sdr)
   6.219 +{
   6.220 +	glAttachShader(prog, sdr);
   6.221 +	assert(glGetError() == GL_NO_ERROR);
   6.222 +}
   6.223 +
   6.224 +int link_program(unsigned int prog)
   6.225 +{
   6.226 +	int linked, info_len, retval = 0;
   6.227 +	char *info_str = 0;
   6.228 +
   6.229 +	glLinkProgram(prog);
   6.230 +	assert(glGetError() == GL_NO_ERROR);
   6.231 +	glGetProgramiv(prog, GL_LINK_STATUS, &linked);
   6.232 +	assert(glGetError() == GL_NO_ERROR);
   6.233 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
   6.234 +	assert(glGetError() == GL_NO_ERROR);
   6.235 +
   6.236 +	if(info_len) {
   6.237 +		if((info_str = malloc(info_len + 1))) {
   6.238 +			glGetProgramInfoLog(prog, info_len, 0, info_str);
   6.239 +			assert(glGetError() == GL_NO_ERROR);
   6.240 +		}
   6.241 +	}
   6.242 +
   6.243 +	if(linked) {
   6.244 +		fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
   6.245 +	} else {
   6.246 +		fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
   6.247 +		retval = -1;
   6.248 +	}
   6.249 +
   6.250 +	free(info_str);
   6.251 +	return retval;
   6.252 +}
   6.253 +
   6.254 +int bind_program(unsigned int prog)
   6.255 +{
   6.256 +	GLenum err;
   6.257 +
   6.258 +	glUseProgram(prog);
   6.259 +	if(prog && (err = glGetError()) != GL_NO_ERROR) {
   6.260 +		/* maybe the program is not linked, try to link first */
   6.261 +		if(err == GL_INVALID_OPERATION) {
   6.262 +			if(link_program(prog) == -1) {
   6.263 +				return -1;
   6.264 +			}
   6.265 +			glUseProgram(prog);
   6.266 +			return glGetError() == GL_NO_ERROR ? 0 : -1;
   6.267 +		}
   6.268 +		return -1;
   6.269 +	}
   6.270 +	return 0;
   6.271 +}
   6.272 +
   6.273 +/* ugly but I'm not going to write the same bloody code over and over */
   6.274 +#define BEGIN_UNIFORM_CODE \
   6.275 +	int loc, curr_prog; \
   6.276 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
   6.277 +	if(curr_prog != prog && bind_program(prog) == -1) { \
   6.278 +		return -1; \
   6.279 +	} \
   6.280 +	if((loc = glGetUniformLocation(prog, name)) != -1)
   6.281 +
   6.282 +#define END_UNIFORM_CODE \
   6.283 +	if(curr_prog != prog) { \
   6.284 +		bind_program(curr_prog); \
   6.285 +	} \
   6.286 +	return loc == -1 ? -1 : 0
   6.287 +
   6.288 +int set_uniform_int(unsigned int prog, const char *name, int val)
   6.289 +{
   6.290 +	BEGIN_UNIFORM_CODE {
   6.291 +		glUniform1i(loc, val);
   6.292 +	}
   6.293 +	END_UNIFORM_CODE;
   6.294 +}
   6.295 +
   6.296 +int set_uniform_float(unsigned int prog, const char *name, float val)
   6.297 +{
   6.298 +	BEGIN_UNIFORM_CODE {
   6.299 +		glUniform1f(loc, val);
   6.300 +	}
   6.301 +	END_UNIFORM_CODE;
   6.302 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/sdr.h	Sun Mar 06 20:31:18 2011 +0200
     7.3 @@ -0,0 +1,34 @@
     7.4 +#ifndef _SDR_H_
     7.5 +#define _SDR_H_
     7.6 +
     7.7 +/* ---- shaders ---- */
     7.8 +unsigned int create_vertex_shader(const char *src);
     7.9 +unsigned int create_pixel_shader(const char *src);
    7.10 +unsigned int create_shader(const char *src, unsigned int sdr_type);
    7.11 +void free_shader(unsigned int sdr);
    7.12 +
    7.13 +unsigned int load_vertex_shader(const char *fname);
    7.14 +unsigned int load_pixel_shader(const char *fname);
    7.15 +unsigned int load_shader(const char *src, unsigned int sdr_type);
    7.16 +
    7.17 +unsigned int get_vertex_shader(const char *fname);
    7.18 +unsigned int get_pixel_shader(const char *fname);
    7.19 +unsigned int get_shader(const char *fname, unsigned int sdr_type);
    7.20 +
    7.21 +int add_shader(const char *fname, unsigned int sdr);
    7.22 +int remove_shader(const char *fname);
    7.23 +
    7.24 +/* ---- gpu programs ---- */
    7.25 +unsigned int create_program(void);
    7.26 +unsigned int create_program_link(unsigned int vs, unsigned int ps);
    7.27 +unsigned int create_program_load(const char *vfile, const char *pfile);
    7.28 +void free_program(unsigned int sdr);
    7.29 +
    7.30 +void attach_shader(unsigned int prog, unsigned int sdr);
    7.31 +int link_program(unsigned int prog);
    7.32 +int bind_program(unsigned int prog);
    7.33 +
    7.34 +int set_uniform_int(unsigned int prog, const char *name, int val);
    7.35 +int set_uniform_float(unsigned int prog, const char *name, float val);
    7.36 +
    7.37 +#endif	/* _SDR_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/stereoplay.c	Sun Mar 06 20:31:18 2011 +0200
     8.3 @@ -0,0 +1,310 @@
     8.4 +#include <stdio.h>
     8.5 +#include <stdlib.h>
     8.6 +#include <string.h>
     8.7 +#include <errno.h>
     8.8 +#include <signal.h>
     8.9 +#include <time.h>
    8.10 +#include <assert.h>
    8.11 +#include <alloca.h>
    8.12 +#include <unistd.h>
    8.13 +#include <fcntl.h>
    8.14 +#include <sys/mman.h>
    8.15 +#include <sys/wait.h>
    8.16 +#include <sys/time.h>
    8.17 +#include <sys/select.h>
    8.18 +#include <X11/Xlib.h>
    8.19 +#include <GL/glew.h>
    8.20 +#include <GL/glut.h>
    8.21 +#include <GL/freeglut_ext.h>
    8.22 +#include <GL/glx.h>
    8.23 +#include "vid.h"
    8.24 +#include "sdr.h"
    8.25 +#include "config.h"
    8.26 +
    8.27 +void cleanup(void);
    8.28 +void decoding_loop(void);
    8.29 +void disp(void);
    8.30 +void reshape(int x, int y);
    8.31 +void keyb(unsigned char key, int x, int y);
    8.32 +void skeyb(int key, int x, int y);
    8.33 +void sig(int s);
    8.34 +void *shmalloc(size_t sz);
    8.35 +
    8.36 +struct video_file *vf;
    8.37 +uint32_t *img;
    8.38 +int vid_xsz, vid_ysz, win_xsz, win_ysz;
    8.39 +unsigned int tex, sdr;
    8.40 +int pfd[2], xsock = -1;
    8.41 +int upd_frame;
    8.42 +int fullscr;
    8.43 +int swap_eyes;
    8.44 +
    8.45 +Display *dpy;
    8.46 +
    8.47 +int main(int argc, char **argv)
    8.48 +{
    8.49 +	int pid;
    8.50 +	char *stereo_combiner, *sdrfile;
    8.51 +
    8.52 +	atexit(cleanup);
    8.53 +
    8.54 +	if(!(vf = vid_open(argv[1]))) {
    8.55 +		return 1;
    8.56 +	}
    8.57 +	vid_xsz = win_xsz = vid_frame_width(vf);
    8.58 +	vid_ysz = win_ysz = vid_frame_height(vf);
    8.59 +
    8.60 +	if(!(img = shmalloc(vid_frame_size(vf)))) {
    8.61 +		perror("failed to allocate frame buffer");
    8.62 +		return 1;
    8.63 +	}
    8.64 +
    8.65 +	if(pipe(pfd) == -1) {
    8.66 +		perror("failed to create a self-pipe");
    8.67 +		return 1;
    8.68 +	}
    8.69 +
    8.70 +	glutInit(&argc, argv);
    8.71 +	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    8.72 +	glutInitWindowSize(win_xsz, win_ysz);
    8.73 +	glutCreateWindow(argv[1]);
    8.74 +
    8.75 +	glutDisplayFunc(disp);
    8.76 +	glutReshapeFunc(reshape);
    8.77 +	glutKeyboardFunc(keyb);
    8.78 +	glutSpecialFunc(skeyb);
    8.79 +
    8.80 +	glewInit();
    8.81 +
    8.82 +	/* create the frame texture */
    8.83 +	glGenTextures(1, &tex);
    8.84 +	glBindTexture(GL_TEXTURE_2D, tex);
    8.85 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    8.86 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    8.87 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    8.88 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    8.89 +	glTexImage2D(GL_TEXTURE_2D, 0, 4, vid_xsz, vid_ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    8.90 +	glEnable(GL_TEXTURE_2D);
    8.91 +
    8.92 +	if(!(stereo_combiner = getenv("STEREO_METHOD"))) {
    8.93 +		stereo_combiner = "redcyan";
    8.94 +	}
    8.95 +
    8.96 +	sdrfile = alloca(strlen(stereo_combiner) + strlen(SDRDIR) + 7);
    8.97 +	sprintf(sdrfile, SDRDIR "/%s.glsl", stereo_combiner);
    8.98 +
    8.99 +	if(!(sdr = create_program_load(0, sdrfile))) {
   8.100 +		return 1;
   8.101 +	}
   8.102 +	bind_program(sdr);
   8.103 +	set_uniform_float(sdr, "left_offs", 0.5);
   8.104 +	set_uniform_float(sdr, "right_offs", 0.0);
   8.105 +
   8.106 +	signal(SIGCHLD, sig);
   8.107 +
   8.108 +	if((pid = fork()) == -1) {
   8.109 +		perror("failed to fork video decoding process");
   8.110 +		return 1;
   8.111 +	} else if(pid) {
   8.112 +		close(pfd[1]);
   8.113 +	} else {
   8.114 +		close(pfd[0]);
   8.115 +		decoding_loop();
   8.116 +		_exit(0);
   8.117 +	}
   8.118 +
   8.119 +	dpy = glXGetCurrentDisplay();
   8.120 +	xsock = ConnectionNumber(dpy);
   8.121 +
   8.122 +	for(;;) {
   8.123 +		int res;
   8.124 +		fd_set rdset;
   8.125 +
   8.126 +		FD_ZERO(&rdset);
   8.127 +		FD_SET(xsock, &rdset);
   8.128 +		FD_SET(pfd[0], &rdset);
   8.129 +
   8.130 +		do {
   8.131 +			res = select((xsock > pfd[0] ? xsock : pfd[0]) + 1, &rdset, 0, 0, 0);
   8.132 +		} while(res == -1 && errno == EINTR);
   8.133 +
   8.134 +		if(FD_ISSET(pfd[0], &rdset)) {
   8.135 +			unsigned char done;
   8.136 +			read(pfd[0], &done, 1);
   8.137 +
   8.138 +			if(done) {
   8.139 +				exit(0);
   8.140 +			} else {
   8.141 +				upd_frame = 1;
   8.142 +				glutPostRedisplay();
   8.143 +			}
   8.144 +		}
   8.145 +
   8.146 +		glutMainLoopEvent();
   8.147 +	}
   8.148 +
   8.149 +	return 0;
   8.150 +}
   8.151 +
   8.152 +void cleanup(void)
   8.153 +{
   8.154 +	if(tex) {
   8.155 +		glDeleteTextures(1, &tex);
   8.156 +	}
   8.157 +	if(img) {
   8.158 +		munmap(img, vid_frame_size(vf));
   8.159 +	}
   8.160 +	if(vf) {
   8.161 +		vid_close(vf);
   8.162 +	}
   8.163 +	close(pfd[0]);
   8.164 +}
   8.165 +
   8.166 +/* decoding_loop() runs in a separate decoding process and communicates
   8.167 + * with the parent process through the pfd[1] pipe.
   8.168 + */
   8.169 +void decoding_loop(void)
   8.170 +{
   8.171 +	unsigned char done = 0;
   8.172 +	struct timespec ts;
   8.173 +	struct timeval tv0, tv;
   8.174 +	unsigned long frame_nsec = vid_frame_interval(vf) * 1000;
   8.175 +	printf("nanosecs per frame: %lu\n", frame_nsec);
   8.176 +
   8.177 +	gettimeofday(&tv0, 0);
   8.178 +
   8.179 +	while(vid_get_frame(vf, img) != -1) {
   8.180 +		write(pfd[1], &done, 1);
   8.181 +
   8.182 +		gettimeofday(&tv, 0);
   8.183 +
   8.184 +		ts.tv_sec = 0;
   8.185 +		ts.tv_nsec = frame_nsec - (tv.tv_usec - tv0.tv_usec) * 1000;
   8.186 +		nanosleep(&ts, 0);
   8.187 +
   8.188 +		gettimeofday(&tv0, 0);
   8.189 +	}
   8.190 +
   8.191 +	done = 1;
   8.192 +	write(pfd[1], &done, 1);
   8.193 +}
   8.194 +
   8.195 +void disp(void)
   8.196 +{
   8.197 +	if(upd_frame) {
   8.198 +		/* frame changed, we must re-upload the texture */
   8.199 +		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, vid_xsz, vid_ysz, GL_BGRA, GL_UNSIGNED_BYTE, img);
   8.200 +		upd_frame = 0;
   8.201 +	}
   8.202 +
   8.203 +	glBegin(GL_QUADS);
   8.204 +	glColor3f(1, 1, 1);
   8.205 +	glTexCoord2f(0, 1); glVertex2f(-1, -1);
   8.206 +	glTexCoord2f(1, 1); glVertex2f(1, -1);
   8.207 +	glTexCoord2f(1, 0); glVertex2f(1, 1);
   8.208 +	glTexCoord2f(0, 0); glVertex2f(-1, 1);
   8.209 +	glEnd();
   8.210 +
   8.211 +	glutSwapBuffers();
   8.212 +}
   8.213 +
   8.214 +void reshape(int x, int y)
   8.215 +{
   8.216 +	if(!fullscr) {
   8.217 +		win_xsz = x;
   8.218 +		win_ysz = y;
   8.219 +	}
   8.220 +
   8.221 +	glViewport(0, 0, x, y);
   8.222 +}
   8.223 +
   8.224 +void keyb(unsigned char key, int x, int y)
   8.225 +{
   8.226 +	switch(key) {
   8.227 +	case 'q':
   8.228 +		exit(0);
   8.229 +
   8.230 +	case 'f':
   8.231 +		fullscr = !fullscr;
   8.232 +		if(fullscr) {
   8.233 +			glutFullScreen();
   8.234 +		} else {
   8.235 +			glutReshapeWindow(win_xsz, win_ysz);
   8.236 +		}
   8.237 +		break;
   8.238 +
   8.239 +	case ' ':
   8.240 +		/* TODO pause/resume */
   8.241 +		break;
   8.242 +
   8.243 +	case 's':
   8.244 +		swap_eyes = !swap_eyes;
   8.245 +		if(swap_eyes) {
   8.246 +			set_uniform_float(sdr, "left_offs", 0.0);
   8.247 +			set_uniform_float(sdr, "right_offs", 0.5);
   8.248 +		} else {
   8.249 +			set_uniform_float(sdr, "left_offs", 0.5);
   8.250 +			set_uniform_float(sdr, "right_offs", 0.0);
   8.251 +		}
   8.252 +		break;
   8.253 +
   8.254 +	default:
   8.255 +		break;
   8.256 +	}
   8.257 +}
   8.258 +
   8.259 +void skeyb(int key, int x, int y)
   8.260 +{
   8.261 +	switch(key) {
   8.262 +	case GLUT_KEY_LEFT:
   8.263 +		/* TODO skip fwd */
   8.264 +		break;
   8.265 +
   8.266 +	case GLUT_KEY_RIGHT:
   8.267 +		/* TODO skip back */
   8.268 +		break;
   8.269 +
   8.270 +	case GLUT_KEY_UP:
   8.271 +		/* TODO skip fwd more */
   8.272 +		break;
   8.273 +
   8.274 +	case GLUT_KEY_DOWN:
   8.275 +		/* TODO skip back more */
   8.276 +		break;
   8.277 +
   8.278 +	case GLUT_KEY_PAGE_UP:
   8.279 +		/* TODO skip fwd a lot */
   8.280 +		break;
   8.281 +
   8.282 +	case GLUT_KEY_PAGE_DOWN:
   8.283 +		/* TODO skip back a lot */
   8.284 +		break;
   8.285 +
   8.286 +	default:
   8.287 +		break;
   8.288 +	}
   8.289 +}
   8.290 +
   8.291 +void sig(int s)
   8.292 +{
   8.293 +	if(s == SIGCHLD) {
   8.294 +		wait(0);
   8.295 +	}
   8.296 +}
   8.297 +
   8.298 +void *shmalloc(size_t sz)
   8.299 +{
   8.300 +	int fd;
   8.301 +	void *shm;
   8.302 +
   8.303 +	if(!(fd = open("/dev/zero", O_RDWR))) {
   8.304 +		return 0;
   8.305 +	}
   8.306 +
   8.307 +	if((shm = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
   8.308 +		shm = 0;
   8.309 +	}
   8.310 +
   8.311 +	close(fd);
   8.312 +	return shm;
   8.313 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/vid.c	Sun Mar 06 20:31:18 2011 +0200
     9.3 @@ -0,0 +1,157 @@
     9.4 +#include <stdio.h>
     9.5 +#include <libavcodec/avcodec.h>
     9.6 +#include <libavformat/avformat.h>
     9.7 +#include <libswscale/swscale.h>
     9.8 +#include "vid.h"
     9.9 +
    9.10 +struct video_file {
    9.11 +	AVFormatContext *avctx;
    9.12 +	AVCodecContext *cctx;
    9.13 +	AVCodec *codec;
    9.14 +	int vstream, audio_stream;
    9.15 +	struct SwsContext *sws;
    9.16 +
    9.17 +	AVFrame *frm, *rgbfrm;
    9.18 +};
    9.19 +
    9.20 +struct video_file *vid_open(const char *fname)
    9.21 +{
    9.22 +	static int initialized;
    9.23 +	struct video_file *vf;
    9.24 +	int i;
    9.25 +
    9.26 +	if(!initialized) {
    9.27 +		av_register_all();
    9.28 +		initialized = 1;
    9.29 +	}
    9.30 +
    9.31 +	if(!(vf = malloc(sizeof *vf))) {
    9.32 +		fprintf(stderr, "open_video(%s): failed to allocate memory: %s\n", fname, strerror(errno));
    9.33 +		return 0;
    9.34 +	}
    9.35 +	memset(vf, 0, sizeof *vf);
    9.36 +
    9.37 +	if(av_open_input_file(&vf->avctx, fname, 0, 0, 0) != 0) {
    9.38 +		fprintf(stderr, "open_video(%s): failed to open file\n", fname);
    9.39 +		vid_close(vf);
    9.40 +		return 0;
    9.41 +	}
    9.42 +
    9.43 +	if(av_find_stream_info(vf->avctx) < 0) {
    9.44 +		fprintf(stderr, "open_video(%s): failed to find stream info\n", fname);
    9.45 +		vid_close(vf);
    9.46 +		return 0;
    9.47 +	}
    9.48 +
    9.49 +	vf->vstream = -1;
    9.50 +	for(i=0; i<vf->avctx->nb_streams; i++) {
    9.51 +		if(vf->avctx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
    9.52 +			vf->vstream = i;
    9.53 +			break;
    9.54 +		}
    9.55 +	}
    9.56 +	if(vf->vstream == -1) {
    9.57 +		fprintf(stderr, "open_video(%s): didn't find a video stream\n", fname);
    9.58 +		vid_close(vf);
    9.59 +		return 0;
    9.60 +	}
    9.61 +	vf->cctx = vf->avctx->streams[vf->vstream]->codec;
    9.62 +
    9.63 +	if(!(vf->codec = avcodec_find_decoder(vf->cctx->codec_id))) {
    9.64 +		fprintf(stderr, "open_video(%s): unsupported codec\n", fname);
    9.65 +		vid_close(vf);
    9.66 +		return 0;
    9.67 +	}
    9.68 +
    9.69 +	if(avcodec_open(vf->cctx, vf->codec) < 0) {
    9.70 +		fprintf(stderr, "open_video(%s): failed to open codec\n", fname);
    9.71 +		vid_close(vf);
    9.72 +		return 0;
    9.73 +	}
    9.74 +
    9.75 +	if(!(vf->frm = avcodec_alloc_frame()) || !(vf->rgbfrm = avcodec_alloc_frame())) {
    9.76 +		fprintf(stderr, "open_video(%s): failed to allocate frame\n", fname);
    9.77 +		vid_close(vf);
    9.78 +		return 0;
    9.79 +	}
    9.80 +
    9.81 +	vf->sws = sws_getContext(vf->cctx->width, vf->cctx->height, vf->cctx->pix_fmt,
    9.82 +			vf->cctx->width, vf->cctx->height, PIX_FMT_RGB32, SWS_POINT, 0, 0, 0);
    9.83 +	if(!vf->sws) {
    9.84 +		fprintf(stderr, "open_video(%s): failed to allocate sws context\n", fname);
    9.85 +		vid_close(vf);
    9.86 +		return 0;
    9.87 +	}
    9.88 +
    9.89 +
    9.90 +	printf("using codec: %s\n", vf->codec->name);
    9.91 +	printf("fps: %f (%u usec frame interval)\n", vid_fps(vf), vid_frame_interval(vf));
    9.92 +	printf("size: %dx%d\n", vid_frame_width(vf), vid_frame_height(vf));
    9.93 +
    9.94 +	return vf;
    9.95 +}
    9.96 +
    9.97 +void vid_close(struct video_file *vf)
    9.98 +{
    9.99 +	if(!vf) return;
   9.100 +
   9.101 +	/* TODO how do we deallocate sws contexts? */
   9.102 +	if(vf->rgbfrm) av_free(vf->rgbfrm);
   9.103 +	if(vf->frm) av_free(vf->frm);
   9.104 +	if(vf->cctx) avcodec_close(vf->cctx);
   9.105 +	if(vf->avctx) av_close_input_file(vf->avctx);
   9.106 +	free(vf);
   9.107 +}
   9.108 +
   9.109 +
   9.110 +float vid_fps(struct video_file *vf)
   9.111 +{
   9.112 +	float inv_tb = (float)vf->cctx->time_base.den / (float)vf->cctx->time_base.num;
   9.113 +	return inv_tb / (float)vf->cctx->ticks_per_frame;
   9.114 +}
   9.115 +
   9.116 +unsigned int vid_frame_interval(struct video_file *vf)
   9.117 +{
   9.118 +	float fps = vid_fps(vf);
   9.119 +	return 1000000 / fps;
   9.120 +}
   9.121 +
   9.122 +int vid_frame_width(struct video_file *vf)
   9.123 +{
   9.124 +	return vf->cctx->width;
   9.125 +}
   9.126 +
   9.127 +int vid_frame_height(struct video_file *vf)
   9.128 +{
   9.129 +	return vf->cctx->height;
   9.130 +}
   9.131 +
   9.132 +size_t vid_frame_size(struct video_file *vf)
   9.133 +{
   9.134 +	return vf->cctx->width * vf->cctx->height * 4;
   9.135 +}
   9.136 +
   9.137 +int vid_get_frame(struct video_file *vf, uint32_t *img)
   9.138 +{
   9.139 +	AVPacket packet;
   9.140 +	int frame_done = 0;
   9.141 +	AVPicture *rgbfrm = (AVPicture*)vf->rgbfrm;
   9.142 +	AVPicture *frm = (AVPicture*)vf->frm;
   9.143 +
   9.144 +	avpicture_fill((AVPicture*)vf->rgbfrm, (uint8_t*)img, PIX_FMT_RGB32, vf->cctx->width, vf->cctx->height);
   9.145 +
   9.146 +	while(av_read_frame(vf->avctx, &packet) >= 0) {
   9.147 +		if(packet.stream_index == vf->vstream) {
   9.148 +			avcodec_decode_video2(vf->cctx, vf->frm, &frame_done, &packet);
   9.149 +
   9.150 +			if(frame_done) {
   9.151 +				sws_scale(vf->sws, frm->data, frm->linesize, 0, vf->cctx->height, rgbfrm->data, rgbfrm->linesize);
   9.152 +				av_free_packet(&packet);
   9.153 +				return 0;
   9.154 +			}
   9.155 +		}
   9.156 +		av_free_packet(&packet);
   9.157 +	}
   9.158 +
   9.159 +	return -1;
   9.160 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/vid.h	Sun Mar 06 20:31:18 2011 +0200
    10.3 @@ -0,0 +1,30 @@
    10.4 +#ifndef VID_H_
    10.5 +#define VID_H_
    10.6 +
    10.7 +#include <inttypes.h>
    10.8 +
    10.9 +struct video_file;
   10.10 +
   10.11 +#ifdef __cplusplus
   10.12 +extern "C" {
   10.13 +#endif
   10.14 +
   10.15 +struct video_file *vid_open(const char *fname);
   10.16 +void vid_close(struct video_file *vf);
   10.17 +
   10.18 +float vid_fps(struct video_file *vf);
   10.19 +
   10.20 +/* returns the interval between frames in microseconds */
   10.21 +unsigned int vid_frame_interval(struct video_file *vf);
   10.22 +
   10.23 +int vid_frame_width(struct video_file *vf);
   10.24 +int vid_frame_height(struct video_file *vf);
   10.25 +size_t vid_frame_size(struct video_file *vf);
   10.26 +
   10.27 +int vid_get_frame(struct video_file *vf, uint32_t *img);
   10.28 +
   10.29 +#ifdef __cplusplus
   10.30 +}
   10.31 +#endif
   10.32 +
   10.33 +#endif	/* VID_H_ */