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_ */