[MPlayer-dev-eng] Re: OpenGL
malc
malc at pulsesoft.com
Sat Sep 16 00:38:23 CEST 2006
Hi,
Following is another version which consumes only one texture unit,
does not claim BACK/AUXn buffers and does not require any particular
framebuffer depth. Some work (pack) uses CPU and is not the fastest
thing in the world, nevertheless performance (due to PBO compatible
texture format) is not so bad on this geforce2mx.
It would be nice to know who came up with 1/4 range idea, so i can
give a proper credit.
/* Clamping idea - Fabian Giesen/ryg
Requires 2 staged register combiner and one texture unit
works only on 420 planar
to build OpenGL, GLUT and GLEW are needed
build: gcc -o yuvi yuvi.c -lGL -lGLEW -lglut
run: ffmpeg -i moo.mpg -s WIDTHxHEIGHT -f rawvideo - | yuvi WIDTH HEIGHT
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#define USE_PBUFFER
enum {NB_TEXS=1};
enum {Y,U,V};
typedef struct {
unsigned int size;
unsigned int w, h, p2w, p2h;
GLuint id;
unsigned char *data;
void *bgra;
GLfloat coords[4][2];
GLenum format, internal_format, type;
struct plane {
unsigned int offset, size;
} planes[3];
GLuint pbuffer;
} 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 pack420 (GLState *s)
{
unsigned int x, y;
unsigned char *py = s->data + s->planes[Y].offset;
unsigned char *pu = s->data + s->planes[U].offset;
unsigned char *pv = s->data + s->planes[V].offset;
unsigned int hw = s->w >> 1;
unsigned int hh = s->h >> 1;
unsigned long long *bgra;
bgra = s->pbuffer
? glMapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY)
: s->bgra
;
for (y = 0; y < hh; ++y) {
unsigned int i;
unsigned char *u1, *v1, *y1;
for (i = 0; i < 2; ++i) {
for (u1 = pu, v1 = pv, y1 = py, x = 0; x < hw; ++x) {
unsigned char u = *u1++;
unsigned char v = *v1++;
unsigned int uvv0 = (u << 24) | (v << 16) | (v << 8);
unsigned long long bgrabgra = uvv0 | *y1++;
*bgra++ = bgrabgra | (unsigned long long) (uvv0 | *y1++) << 32;
}
py += s->w;
}
pu += hw;
pv += hw;
}
if (s->pbuffer) {
glUnmapBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB);
}
}
static void (*pack) (GLState *) = pack420;
static void setup_combiners (GLState *s)
{
glEnable (GL_REGISTER_COMBINERS_NV);
glCombinerParameterfvNV (GL_CONSTANT_COLOR0_NV, yuv2rgb[0]);
glCombinerParameterfvNV (GL_CONSTANT_COLOR1_NV, yuv2rgb[1]);
glCombinerInputNV (GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV,
GL_TEXTURE0_ARB, GL_UNSIGNED_IDENTITY_NV, GL_BLUE);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
GL_TEXTURE0_ARB, GL_HALF_BIAS_NORMAL_NV, GL_ALPHA);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
GL_CONSTANT_COLOR0_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
GL_TEXTURE0_ARB, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
glCombinerInputNV (GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
GL_CONSTANT_COLOR1_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
glCombinerOutputNV (GL_COMBINER0_NV,
GL_RGB,
GL_DISCARD_NV,
GL_DISCARD_NV,
GL_SPARE0_NV,
GL_SCALE_BY_FOUR_NV,
GL_NONE,
GL_FALSE,
GL_FALSE,
GL_FALSE);
glCombinerInputNV (GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV,
GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
glCombinerInputNV (GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV,
GL_SPARE0_NV, GL_SIGNED_IDENTITY_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 tex_params (void)
{
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
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 (unsigned int w, unsigned int h, int xshift, int yshift)
{
GLState *s;
unsigned int i;
GLuint texids[NB_TEXS];
struct plane *plane;
GLfloat tw, th;
s = malloc (sizeof (*s));
if (!s) {
perror ("malloc");
exit (EXIT_FAILURE);
}
s->format = GL_BGRA;
s->internal_format = GL_RGBA;
s->type = GL_UNSIGNED_INT_8_8_8_8_REV;
s->w = w;
s->h = h;
s->planes[Y].size = w * h;
s->planes[Y].offset = 0;
s->planes[U] = s->planes[Y];
s->planes[U].size >>= (xshift + yshift);
s->planes[U].offset = s->planes[Y].size;
s->planes[V] = s->planes[U];
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);
}
#ifndef USE_PBUFFER
s->bgra = malloc (w * 4 * h);
if (!s->bgra) {
perror ("malloc temp");
exit (EXIT_FAILURE);
}
#else
s->bgra = NULL;
#endif
glGenTextures (1, texids);
s->id = texids[0];
s->p2w = (w & (w - 1)) ? nlpo2 (w) : w;
s->p2h = (h & (h - 1)) ? nlpo2 (h) : h;
tw = (double) w / s->p2w;
th = (double) h / s->p2h;
s->coords[0][0] = 0.0; s->coords[0][1] = 0.0;
s->coords[1][0] = tw; s->coords[1][1] = 0.0;
s->coords[2][0] = tw; s->coords[2][1] = th;
s->coords[3][0] = 0.0; s->coords[3][1] = th;
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, s->id);
tex_params ();
glTexImage2D (GL_TEXTURE_2D, 0, s->internal_format,
s->p2w, s->p2h, 0, s->format,
s->type, NULL);
#ifdef USE_PBUFFER
glGenBuffers (1, &s->pbuffer);
glBindBufferARB (GL_PIXEL_UNPACK_BUFFER_ARB, s->pbuffer);
glBufferDataARB (GL_PIXEL_UNPACK_BUFFER_ARB, w * h * 4, NULL,
GL_STREAM_DRAW);
#else
s->pbuffer = 0;
#endif
setup_combiners (s);
return s;
}
static void upload (GLState *s)
{
static const GLint als[4] = {4, 1, 2, 1};
if (fread (s->data, s->size, 1, stdin) - 1) {
if (feof (stdin)) {
exit (EXIT_SUCCESS);
}
perror ("fread");
exit (EXIT_FAILURE);
}
pack (s);
glBindTexture (GL_TEXTURE_2D, s->id);
glPixelStorei (GL_UNPACK_ALIGNMENT, als[s->w & 3]);
glPixelStorei (GL_UNPACK_ROW_LENGTH, s->w );
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
s->w, s->h,
s->format, s->type, s->bgra);
}
static void draw (GLState *s)
{
unsigned int i;
glBegin (GL_QUADS);
{
for (i = 0; i < 4; ++i) {
glTexCoord2fv (s->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: yuvi width height < rawvideo.i420\n");
fprintf (stderr,
" OR: ffmpeg -i moo.mpg -f rawvideo -s WxH - | yuvi W H\n");
exit (EXIT_FAILURE);
}
w = atoi (argv[1]);
h = atoi (argv[2]);
glutInitDisplayMode (GLUT_SINGLE);
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