简体   繁体   中英

Using OpenGL to write to a file rather than draw on the screen

I'm trying to create an rgb to yuv image shader. I have the image drawn on the screen using SDL but rather than that I want the output of the shader to be written into a test.yuv file. I'm still a beginner in OpenGL, I was wondering if that is possible or not? I made an attempt to get the output into a buffer but it was unsucessful. Its in my code labelled "MY ATTEMPT"

int main()
{
    void* buf //raw image file

    SDL_Surface *Win=NULL;
    SDL_Event evt;
    int i;
    GLhandleARB FSHandle,PHandle;
    char *s;

    const char *FProgram=
            "uniform sampler2DRect rgba;\n"
            "vec4 YUV;\n"

            "void main(void) {\n"
            "vec4 new_rgba = texture2DRect(rgba, gl_TexCoord[0].xy);\n"

            "mat4 RGBtoYUV = mat4(0.257,  0.439, -0.148, 0.0, 0.504, -0.368, -0.291, 0.0, 0.098, -0.071,  0.439, 0.0, 0.0625, 0.500,  0.500, 1.0 );\n"

            "YUV = RGBtoYUV * new_rgba;"

            "gl_FragColor = YUV;"

            "}\n";

    if(!SDL_Init(SDL_INIT_VIDEO)) {

        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);

        Win=SDL_SetVideoMode(B_WIDTH,B_HEIGHT,32,SDL_HWSURFACE|SDL_ANYFORMAT|SDL_OPENGL);

        if(Win) {


            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0,B_WIDTH,0,B_HEIGHT,-1,1);
            glViewport(0,0,B_WIDTH,B_HEIGHT);
            glClearColor(0,0,0,0);
            glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);

            /* Set up program objects. */
            PHandle=glCreateProgramObjectARB();
            FSHandle=glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);

            /* Compile the shader. */
            glShaderSourceARB(FSHandle,1,&FProgram,NULL);
            glCompileShaderARB(FSHandle);

            /* Print the compilation log. */
            glGetObjectParameterivARB(FSHandle,GL_OBJECT_COMPILE_STATUS_ARB,&i);
            s=new char(32768);
            glGetInfoLogARB(FSHandle,32768,NULL,s);
            printf("Compile Log: %s\n", s);
            delete[] s;

            /* Create a complete program object. */
            glAttachObjectARB(PHandle,FSHandle);
            glLinkProgramARB(PHandle);

            /* And print the link log. */
            s=new char(32768);
            glGetInfoLogARB(PHandle,32768,NULL,s);
            printf("Link Log: %s\n", s);
            delete[] s;

            /* Finally, use the program. */
            glUseProgramObjectARB(PHandle);

            /* This might not be required, but should not hurt. */
            glEnable(GL_TEXTURE_2D);

            /* Select texture unit 1 as the active unit and bind the U texture. */
            glActiveTexture(GL_TEXTURE1);

            GLuint texColorBuffer;
            glGenTextures(1, &texColorBuffer);

            glBindTexture(GL_TEXTURE_RECTANGLE_NV,texColorBuffer);
            glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
            glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
            glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
            glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_RGBA8,1920,1080,0,GL_BGRA,GL_UNSIGNED_BYTE, buf);


            i=glGetUniformLocationARB(PHandle,"rgba");
            glUniform1iARB(i,1);

//MY ATTEMPT TO GET THE BUFFER TO WRITE INTO A FILE.
            QByteArray* raw_img;
            glGetTexImage(GL_TEXTURE_RECTANGLE_NV, 0, GL_RGBA8,GL_UNSIGNED_BYTE, raw_img);

            QFile test("/tmp/wajeeh.yuv");
            test.open(QFile::WriteOnly);
            test.write(*raw_img);
            test.close();

            /* Simple loop, just draws the image and waits for quit. */
            while(!Quit) {
                if(SDL_PollEvent(&evt)) {
                    switch(evt.type) {
                    case  SDL_KEYDOWN:
                    case  SDL_QUIT:
                        Quit=1;
                        break;
                    }
                }


                glClear(GL_COLOR_BUFFER_BIT);

                /* Draw image (again and again). */

                glBegin(GL_QUADS);
                glTexCoord2i(0,1080);
                glVertex2i(0,0);
                glTexCoord2i(1920,1080);
                glVertex2i(B_WIDTH,0);
                glTexCoord2i(1920,0);
                glVertex2i(B_WIDTH,B_HEIGHT);
                glTexCoord2i(0,0);
                glVertex2i(0,B_HEIGHT);
                glEnd();



                /* Flip buffers. */

                glFlush();
                SDL_GL_SwapBuffers();

                SDL_Delay(50);
            } /* while(!Quit) */

            /* Clean up before exit. */

            glUseProgramObjectARB(0);
            glDeleteObjectARB(PHandle);



        } else {
            fprintf(stderr,"Unable to create primary surface. \"%s\".\n",SDL_GetError());
        }
        SDL_Quit();
    } else {
        fprintf(stderr,"Initialisation failed. \"%s\".\n",SDL_GetError());
    }

    return(0);
}

The general idea you should look for is the offscreen rendering . Instead of using the default framebuffer opengl provides you to render to, you can create other framebuffers with desired size, and set them as render targets. After that you can glReadPixels and save the pixmap to the format you need.

More examples here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM