[MPlayer-dev-eng] Re: OpenGL

malc av1474 at comtv.ru
Sat Sep 16 21:49:15 CEST 2006


Hi,

Following is yet another version that does not require three texture untis. It
does some shuffling on the CPU but unlike the previous version the shuffling is
much simpler and requires less memory. However texture format in this case does
not admit PBO.

Following page summarizes the aproaches and also contains reference SDL based
version, should some feel the need to make some performance analysis.

http://boblycat.org/~malc/code/patches/mplayer/nvrc/index.html
(at the time of the writing server experienced some difficulties replacing
http with https seemed to work though)

/*  Clamping idea - Fabian Giesen/ryg
    Requires 2 staged register combiner and two texture units
    to build OpenGL, GLUT and GLEW are needed
    build: gcc -o yuvla yuvla.c -lGL -lGLEW -lglut
    run: ffmpeg -i moo.mpg -s WIDTHxHEIGHT -f rawvideo - | yuvla 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 DBUFFER
enum {NB_TEXS=2};
enum {Y,U,V,NB_PLANES};
typedef struct {
    unsigned int size;
    unsigned char *data;
    void *la;
    unsigned int offsets[NB_PLANES];
    struct plane {
        GLuint id;
        unsigned int w, h, p2w, p2h;
        unsigned int size;
        GLenum format, internal_format, type;
        GLenum unit;
        GLfloat coords[4][2];
    } planeY, planeUV;
} 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 pack420la (GLState *s, void *ptrs[2])
{
    unsigned int i, size = s->planeUV.size;
    unsigned char *pu = s->data + s->offsets[U];
    unsigned char *pv = s->data + s->offsets[V];
    unsigned char *la;
    char *ptrY, *ptrUV;

    la = s->la;
    ptrY = s->data;
    ptrUV = la;

    for (i = 0; i < size; ++i) {
        *la++ = *pu++;
        *la++ = *pv++;
    }

    ptrs[0] = ptrY;
    ptrs[1] = ptrUV;
}

static void (*pack) (GLState *, void *[2]) = pack420la;

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_RGB, GL_VARIABLE_A_NV,
                       s->planeUV.unit, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
    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,
                       s->planeUV.unit, GL_HALF_BIAS_NORMAL_NV, GL_ALPHA);
    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,
                       s->planeY.unit, 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 unsigned int choosepo2 (unsigned int x)
{
    return (x & (x - 1)) ? nlpo2 (x) : x;
}

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);
    }

    glGenTextures (NB_TEXS, texids);

    plane = &s->planeY;
    plane->format = GL_ALPHA;
    plane->internal_format = GL_ALPHA8;
    plane->type = GL_UNSIGNED_BYTE;
    plane->w = w;
    plane->h = h;
    plane->id = texids[0];
    plane->unit = GL_TEXTURE0_ARB;

    plane = &s->planeUV;
    plane->format = GL_LUMINANCE_ALPHA;
    plane->internal_format = GL_LUMINANCE8_ALPHA8;
    plane->type = GL_UNSIGNED_BYTE;
    plane->w = w >> xshift;
    plane->h = h >> yshift;
    plane->id = texids[1];
    plane->unit = GL_TEXTURE1_ARB;

    for (i = 0; i < 2; ++i) {
        plane = i ? &s->planeUV : &s->planeY;

        plane->size = plane->w * plane->h;
        plane->p2w = choosepo2 (plane->w);
        plane->p2h = choosepo2 (plane->h);
        tw = (GLfloat) plane->w / plane->p2w;
        th = (GLfloat) plane->h / 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, plane->internal_format,
                      plane->p2w, plane->p2h, 0, plane->format,
                      plane->type, NULL);
    }

    s->offsets[Y] = 0;
    s->offsets[U] = s->planeY.size;
    s->offsets[V] = s->offsets[U] + s->planeUV.size;

    s->size = s->planeY.size + (s->planeUV.size << 1);
    s->data = malloc (s->size);
    if (!s->data) {
        perror ("malloc");
        exit (EXIT_FAILURE);
    }

    s->la = malloc (s->size);
    if (!s->la) {
        perror ("malloc temp");
        exit (EXIT_FAILURE);
    }
    setup_combiners (s);
    return s;
}

static void upload (GLState *s)
{
    unsigned int i;
    static const GLint als[4] = {4, 1, 2, 1};
    struct plane *plane;
    void *ptrs[2];

    if (fread (s->data, s->size, 1, stdin) - 1) {
        if (feof (stdin)) {
            exit (EXIT_SUCCESS);
        }
        perror ("fread");
        exit (EXIT_FAILURE);
    }

    pack (s, ptrs);

    for (i = 0; i < 2; ++i) {
        plane = i ? &s->planeUV : &s->planeY;
        glActiveTextureARB (plane->unit);
        glBindTexture (GL_TEXTURE_2D, plane->id);
        glPixelStorei (GL_UNPACK_ALIGNMENT, als[plane->w & 3]);
        glPixelStorei (GL_UNPACK_ROW_LENGTH, plane->w);
        glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
                         plane->w, plane->h,
                         plane->format, plane->type, ptrs[i]);
    }
}

static void draw (GLState *s)
{
    unsigned int i;

    glBegin (GL_QUADS);
    {
        for (i = 0; i < 4; ++i) {
            glMultiTexCoord2fvARB (s->planeY.unit, s->planeY.coords[i]);
            glMultiTexCoord2fvARB (s->planeUV.unit, s->planeUV.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 ();
}

static void display_cb (void)
{
    glutSwapBuffers ();
}

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]);

#ifdef DBUFFER
    glutInitDisplayMode (GLUT_DOUBLE);
#else
    glutInitDisplayMode (GLUT_SINGLE);
#endif
    glutInitWindowSize (w, h);
    glutCreateWindow ("YUV2RGB(rc2tu2la)");
    glewInit ();

    global_state = init (w, h, 1, 1);

    glutReshapeFunc (reshape_cb);
#ifdef DBUFFER
    glutDisplayFunc (display_cb);
#endif
    glutKeyboardFunc (keyboard_cb);
    glutIdleFunc (idle_cb);
    glutMainLoop ();
    exit (EXIT_SUCCESS);
}





More information about the MPlayer-dev-eng mailing list