Created
December 9, 2013 13:37
-
-
Save roxlu/7872352 to your computer and use it in GitHub Desktop.
Mac 10.9 using YUV input with opengl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PHOTOBOOTH_SHADERS_H | |
#define PHOTOBOOTH_SHADERS_H | |
#include <opengl/Headers.h> | |
#include <math/Math.h> | |
// -------------------------------------------------- | |
static const char* P_VS = "" | |
"#version 150\n" | |
"uniform mat4 u_pm;" | |
"in vec4 a_pos;" | |
"void main() {" | |
" gl_Position = u_pm * a_pos;" | |
"}" | |
""; | |
static const char* P_FS = "" | |
"#version 150\n" | |
"out vec4 fragcolor; " | |
"void main() {" | |
" fragcolor = vec4(0.5, 0.3, 0.2, 1.0); " | |
"}" | |
""; | |
static const char* PT_VS = "" | |
"#version 150\n" | |
"uniform mat4 u_pm;" | |
"in vec4 a_pos;" | |
"in vec2 a_tex;" | |
"out vec2 v_tex;" | |
"void main() {" | |
" gl_Position = u_pm * a_pos;" | |
" v_tex = a_tex;" | |
"}" | |
""; | |
static const char* PT_FS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex;" | |
"out vec4 fragcolor;" | |
"in vec2 v_tex;" | |
"void main() {" | |
" fragcolor = vec4(0.5, 1.0, 0.2, 1.0); " | |
"}" | |
""; | |
static const char* YUV_FS = "" | |
"#version 150\n" | |
"uniform sampler2D u_tex;" | |
"in vec2 v_tex;" | |
"out vec4 fragcolor; " | |
"" | |
"const vec3 R_cf = vec3(1.164383, 0.000000, 1.596027);" | |
"const vec3 G_cf = vec3(1.164383, -0.391762, -0.812968);" | |
"const vec3 B_cf = vec3(1.164383, 2.017232, 0.000000);" | |
"const vec3 offset = vec3(-0.0625, -0.5, -0.5);" | |
"void main() {" | |
" vec3 tc = texture(u_tex, v_tex).rgb;" | |
" vec3 yuv = vec3(tc.g, tc.b, tc.r);" | |
" yuv += offset;" | |
" fragcolor.r = dot(yuv, R_cf);" | |
" fragcolor.g = dot(yuv, G_cf);" | |
" fragcolor.b = dot(yuv, B_cf);" | |
" fragcolor.a = 1.0;" | |
"}" | |
""; | |
// -------------------------------------------------- | |
class PhotoBooth; | |
class Shaders { | |
public: | |
Shaders(PhotoBooth& booth); | |
~Shaders(); | |
bool setup(); | |
public: | |
PhotoBooth& booth; | |
/* VertexP shader */ | |
GLuint vert_p; | |
GLuint frag_p_debug; | |
GLuint prog_p_debug; | |
/* VertexPT shader */ | |
GLuint vert_pt; | |
GLuint frag_pt; | |
GLuint prog_pt; | |
/* YUYV shader */ | |
GLuint frag_yuv; | |
GLuint prog_yuv; | |
Mat4 ortho_matrix; | |
}; | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <photobooth/Webcam.h> | |
#include <photobooth/PhotoBooth.h> | |
void frame_callback(void* pixels, size_t nbytes, void* user) { | |
Webcam* c = static_cast<Webcam*>(user); | |
assert(c->yuv_pixels); | |
uv_mutex_lock(&c->yuv_mutex); | |
memcpy((char*)c->yuv_pixels, (char*)pixels, nbytes); | |
c->has_new_frame = true; | |
uv_mutex_unlock(&c->yuv_mutex); | |
} | |
// --------------------------------------------------- | |
Webcam::Webcam(PhotoBooth& booth) | |
:booth(booth) | |
,cam_vao(0) | |
,cam_vbo(0) | |
,cam_tex(0) | |
,has_new_frame(false) | |
,yuv_pixels(NULL) | |
{ | |
stop(); | |
uv_mutex_init(&yuv_mutex); | |
} | |
Webcam::~Webcam() { | |
printf("@TODO: Stop capture!.\n"); | |
uv_mutex_destroy(&yuv_mutex); | |
} | |
bool Webcam::setup() { | |
// setup video capture. | |
VideoCaptureSettings cfg; | |
cfg.width = 1280; | |
cfg.height = 720; | |
cfg.in_pixel_format = VIDEOCAPTURE_FMT_UYVY422; | |
cfg.fps = 30.0f; | |
if(!cap.openDevice(0, cfg, frame_callback, this)) { | |
printf("Cannot setup the webcam.\n"); | |
return false; | |
} | |
// create rectangle to draw webcam in. | |
glGenVertexArrays(1, &cam_vao); | |
glBindVertexArray(cam_vao); | |
glGenBuffers(1, &cam_vbo); | |
glBindBuffer(GL_ARRAY_BUFFER, cam_vbo); | |
glEnableVertexAttribArray(0); // pos; | |
glEnableVertexAttribArray(1); // tex | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexPT), (GLvoid*)0); | |
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(VertexPT), (GLvoid*)12); | |
Vertices<VertexPT> verts; | |
verts.push_back(VertexPT(Vec3(0.0f, 0.0f, 0.0f), Vec2(0.0f, 1.0f))); // bottom left | |
verts.push_back(VertexPT(Vec3(0.0f, cfg.height, 0.0f), Vec2(0.0f, 0.0f))); // top left | |
verts.push_back(VertexPT(Vec3(cfg.width, 0.0f, 0.0f), Vec2(1.0f, 1.0f))); // bottom right | |
verts.push_back(VertexPT(Vec3(cfg.width, cfg.height, 0.0f), Vec2(1.0f, 0.0f))); // top right | |
glBufferData(GL_ARRAY_BUFFER, verts.getNumBytes(), verts.getPtr(), GL_STATIC_DRAW); | |
glBindVertexArray(0); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
// Webcam texture | |
glGenTextures(1, &tex_yuv); | |
glBindTexture(GL_TEXTURE_2D, tex_yuv); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cfg.width, cfg.height, 0, | |
GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, 0); | |
rx_set_texture_parameters(); | |
glBindTexture(GL_TEXTURE_2D, 0); | |
yuv_pixels = new unsigned char[cfg.width * cfg.height * 2]; | |
if(!yuv_pixels) { | |
printf("Cannot allocate yuv pixel container.\n"); | |
return false; | |
} | |
return true; | |
} | |
void Webcam::update() { | |
uv_mutex_lock(&yuv_mutex); | |
{ | |
if(has_new_frame) { | |
glBindTexture(GL_TEXTURE_2D, tex_yuv); | |
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cap.getWidth(), cap.getHeight(), | |
GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, yuv_pixels); | |
has_new_frame = false; | |
} | |
} | |
uv_mutex_unlock(&yuv_mutex); | |
cap.update(); | |
} | |
void Webcam::draw() { | |
glBindVertexArray(cam_vao); | |
glUseProgram(booth.shaders.prog_yuv); | |
glUniformMatrix4fv(glGetUniformLocation(booth.shaders.prog_yuv, "u_pm"), 1, GL_FALSE, booth.shaders.ortho_matrix.getPtr()); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, tex_yuv); | |
glUniform1i(glGetUniformLocation(booth.shaders.prog_yuv, "u_tex"), 0); | |
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
} | |
bool Webcam::start() { | |
if(!cap.startCapture()) { | |
printf("Cannot start the capture.\n"); | |
return false; | |
} | |
return true; | |
} | |
bool Webcam::stop() { | |
if(!cap.stopCapture()) { | |
printf("Cannot stop the capture.\n"); | |
return false; | |
} | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PHOTOBOOTH_WEBCAM_H | |
#define PHOTOBOOTH_WEBCAM_H | |
#include <videocapture/VideoCapture.h> | |
#include <opengl/Includes.h> | |
#include <uv.h> | |
void frame_callback(void* pixels, size_t nbytes, void* user); | |
class PhotoBooth; | |
class Webcam { | |
public: | |
Webcam(PhotoBooth& booth); | |
~Webcam(); | |
bool setup(); | |
bool start(); | |
bool stop(); | |
void update(); | |
void draw(); | |
private: | |
PhotoBooth& booth; | |
VideoCapture cap; | |
/* GL objects for drawing the cam */ | |
GLuint tex_yuv; | |
GLuint cam_vao; | |
GLuint cam_vbo; | |
GLuint cam_tex; | |
public: | |
unsigned char* yuv_pixels; | |
uv_mutex_t yuv_mutex; | |
bool has_new_frame; | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment