[MPlayer-dev-eng] OpenGL
malc
malc at pulsesoft.com
Wed Sep 6 16:28:39 CEST 2006
Hi,
Currently OpenGL video output with hardware yuv2rgb conversion
requires 3 texture units. Following is the version that works
with 2 TUs and a back-buffer (i.e. works on GeForce2MX here).
Perhaps someone could integrate it into existing framework.
/* Clamping idea/initial combiner implementation - Fabian Giesen/ryg
Requires 2 staged register combiner, 2 texture units and a back buffer
24 bit frame buffer is required(5 bits of precision for U+V is not enough)
to build OpenGL, GLUT and GLEW are needed
build: gcc -o yuv yuv.c -lGL -lGLEW -lglut
run: ffmpeg -i moo.mpg -s WIDTHxHEIGHT -f rawvideo - | yuv WIDTH HEIGHT
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
enum {Y,U,V,T,NB_TEXS};
typedef struct {
unsigned int size;
unsigned int w, h;
char *data;
struct plane {
unsigned int w, h, p2w, p2h, offset, size;
GLenum unit;
GLuint id;
GLfloat coords[4][2];
} planes[4];
} GLState;
static GLState *global_state;
static GLint quad[] = {-1, 1, 1, 1, 1, -1, -1, -1};
static GLfloat yuv2rgb[2][4] = {
{0.500000f, 0.413650f, 0.944700f, 0.f},
{0.851850f, 0.320550f, 0.500000f, 1.f},
};
/* http://aggregate.org/MAGIC/ */
static unsigned int nlpo2 (unsigned int x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x + 1;
}
static void nvrc2tu2_combine_UV (void)
{
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
GL_TEXTURE0_ARB, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
GL_CONSTANT_COLOR0_NV, GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
GL_TEXTURE1_ARB, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
GL_CONSTANT_COLOR1_NV, GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
GL_SPARE0_NV, GL_SIGNED_IDENTITY_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV,
GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV,
GL_ZERO, GL_HALF_BIAS_NEGATE_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV,
GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
glCombinerParameteriNV (GL_NUM_GENERAL_COMBINERS_NV, 2);
}
static void nvrc2tu2_combine_final (void)
{
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
GL_TEXTURE1_ARB, GL_EXPAND_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_RGB);
glCombinerParameteriNV (GL_NUM_GENERAL_COMBINERS_NV, 1);
}
static void tex_params (void)
{
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
static GLState *init (GLsizei w, GLsizei h, int xshift, int yshift)
{
GLState *s;
size_t i;
GLuint texids[NB_TEXS];
struct plane *plane;
s = malloc (sizeof (*s));
if (!s) {
perror ("malloc");
exit (EXIT_FAILURE);
}
s->w = w;
s->h = h;
s->planes[Y].w = w;
s->planes[Y].h = h;
s->planes[Y].size = w * h;
s->planes[Y].offset = 0;
s->planes[U] = s->planes[0];
s->planes[U].w >>= xshift;
s->planes[U].h >>= yshift;
s->planes[U].size >>= 2;
s->planes[U].offset = s->planes[Y].size;
s->planes[V] = s->planes[1];
s->planes[V].offset += s->planes[U].size;
s->size = s->planes[Y].size + (s->planes[U].size << 1);
s->data = malloc (s->size);
if (!s->data) {
perror ("malloc");
exit (EXIT_FAILURE);
}
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glGenTextures (NB_TEXS, texids);
for (i = 0; i < 3; ++i) {
GLfloat tw, th;
unsigned int ww, hh;
GLenum units[3] = {GL_TEXTURE0_ARB, GL_TEXTURE0_ARB, GL_TEXTURE1_ARB};
plane = &s->planes[i];
ww = plane->w;
hh = plane->h;
plane->unit = i[units];
plane->id = texids[i];
plane->p2w = (ww & (ww - 1)) ? nlpo2 (ww) : ww;
plane->p2h = (hh & (hh - 1)) ? nlpo2 (hh) : hh;
tw = (double) ww / plane->p2w;
th = (double) hh / plane->p2h;
plane->coords[0][0] = 0.0; plane->coords[0][1] = 0.0;
plane->coords[1][0] = tw; plane->coords[1][1] = 0.0;
plane->coords[2][0] = tw; plane->coords[2][1] = th;
plane->coords[3][0] = 0.0; plane->coords[3][1] = th;
glActiveTextureARB (plane->unit);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, plane->id);
tex_params ();
glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE8,
plane->p2w, plane->p2h, 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, NULL);
}
plane = &s->planes[T];
*plane = s->planes[U];
plane->id = texids[T];
plane->unit = GL_TEXTURE1_ARB;
glBindTexture (GL_TEXTURE_2D, plane->id);
tex_params ();
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8,
plane->p2w, plane->p2h, 0, GL_RGB,
GL_INT, NULL);
glEnable (GL_REGISTER_COMBINERS_NV);
glCombinerParameterfvNV (GL_CONSTANT_COLOR0_NV, yuv2rgb[0]);
glCombinerParameterfvNV (GL_CONSTANT_COLOR1_NV, yuv2rgb[1]);
return s;
}
static void upload (GLState *s)
{
size_t i;
char *ptr;
if (fread (s->data, s->size, 1, stdin) - 1) {
if (feof (stdin)) {
exit (EXIT_SUCCESS);
}
perror ("fread");
exit (EXIT_FAILURE);
}
ptr = s->data;
for (i = 0; i < 3; ++i) {
GLint als[4] = {4, 1, 2, 1};
struct plane *plane = &s->planes[i];
glBindTexture (GL_TEXTURE_2D, plane->id);
glPixelStorei (GL_UNPACK_ALIGNMENT, als[plane->offset & 3]);
if (plane->p2w != plane->w) {
glPixelStorei (GL_UNPACK_ROW_LENGTH, plane->w);
}
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
plane->w, plane->h,
GL_LUMINANCE, GL_UNSIGNED_BYTE,
ptr);
ptr += plane->size;
}
}
static void draw (GLState *s)
{
int i;
glPushMatrix ();
glLoadIdentity ();
glRotatef (180.0, 1.0, 0.0, 0.0);
glViewport (0, 0, s->planes[T].w, s->planes[T].h);
glDrawBuffer (GL_BACK);
nvrc2tu2_combine_UV ();
glActiveTextureARB (s->planes[U].unit);
glBindTexture (GL_TEXTURE_2D, s->planes[U].id);
glActiveTextureARB (s->planes[V].unit);
glBindTexture (GL_TEXTURE_2D, s->planes[V].id);
glBegin (GL_QUADS);
{
for (i = 0; i < 4; ++i) {
glMultiTexCoord2fvARB (s->planes[U].unit, s->planes[1].coords[i]);
glMultiTexCoord2fvARB (s->planes[V].unit, s->planes[2].coords[i]);
glVertex2iv (quad + i * 2);
}
}
glEnd ();
glReadBuffer (GL_BACK);
glActiveTextureARB (s->planes[T].unit);
glBindTexture (GL_TEXTURE_2D, s->planes[T].id);
glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 0, 0,
s->planes[T].w, s->planes[T].h);
glPopMatrix ();
glViewport (0, 0,
glutGet (GLUT_WINDOW_WIDTH), glutGet (GLUT_WINDOW_HEIGHT));
glDrawBuffer (GL_FRONT);
glActiveTextureARB (s->planes[Y].unit);
glBindTexture (GL_TEXTURE_2D, s->planes[Y].id);
nvrc2tu2_combine_final ();
glBegin (GL_QUADS);
{
for (i = 0; i < 4; ++i) {
glMultiTexCoord2fvARB (s->planes[Y].unit, s->planes[Y].coords[i]);
glMultiTexCoord2fvARB (s->planes[T].unit, s->planes[T].coords[i]);
glVertex2iv (quad + i * 2);
}
}
glEnd ();
}
static void keyboard_cb (unsigned char c, int huh, int doh)
{
switch (c) {
case 27:
case 'q':
exit (EXIT_SUCCESS);
}
}
static void idle_cb (void)
{
GLState *s = global_state;
upload (s);
draw (s);
glutPostRedisplay ();
}
static void reshape_cb (int w, int h)
{
glViewport (0, 0, w, h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
}
int main (int argc, char **argv)
{
int w, h;
glutInit (&argc, argv);
if (argc < 3) {
fprintf (stderr, "usage: yuv width height < rawvideo.i420\n");
fprintf (stderr,
" OR: ffmpeg -i moo.mpg -f rawvideo -s WxH - | yuv W H\n");
exit (EXIT_FAILURE);
}
w = atoi (argv[1]);
h = atoi (argv[2]);
glutInitDisplayMode (GLUT_DOUBLE);
glutInitWindowSize (w, h);
glutCreateWindow ("YUV2RGB");
glewInit ();
global_state = init (w, h, 1, 1);
glutReshapeFunc (reshape_cb);
glutKeyboardFunc (keyboard_cb);
glutIdleFunc (idle_cb);
glutMainLoop ();
exit (EXIT_SUCCESS);
}
More information about the MPlayer-dev-eng
mailing list