glReadPixels读取显存数据并保存图像

glReadPixels: 如果你想将渲染的结果保存下来,你可以使用glReadPixels将图像内容从现存读取到内存中,需要注意:仅限于读取Color Buffer,无法读取Depth Buffer和Stencil Buffer,当调用glReadPixels时,可以将Color Buffer中的像素值保存到预分配的内存缓冲区中。

函数定义:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
x, y: specify the viewport coordinates of the lower-left corner of the pixel rectangle read from the color buffer.

width,height: specify the dimensions of the pixel rectangle read from the color buffer.


format: specifies the pixel format that you would like returned. Three formats are available: GL_RGBA, GL_RGBA_INTEGER, and the value returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT, which is an implementation-specific pixel format.

type: specifies the data type of the pixels returned. Five types are available: GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_INT, GL_FLOAT, and the value returned from querying GL_IMPLEMENTATION_COLOR_READ_TYPE, which is an implementation-specific pixel type. pixels: a contiguous array of bytes that contain the values read from the color buffer after glReadPixels returns.

下面分几种情况讲解glReadPixels的使用方式:

1. 从GL_TEXTURE_2D中读取:

当从GL_TEXTURE_2D读取时,因为有可能当前Context并没有FrameBuffer绑定,或者FrameBuffer绑定的并不是我们需要读取的Texture,所以最好的方式是创建一个临时FrameBuffer,在临时的FrameBuffer上绑定要读取的Texture,并在使用临时FrameBuffer之前,查询当前绑定的FrameBuffer,并在读取完成后恢复当前绑定的FrameBuffer。

GLuint Tmp_Framebuffer = 0;
glGenFramebuffers ( 1, &TMP_Framebuffer );

/******* IN Rendering LOOP Begin**************/
    GLint defaultFramebuffer = 0;
    glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );

    glBindFramebuffer ( GL_FRAMEBUFFER, G_Framebuffer );
    // textureId:  要读取的TextureID
    glFramebufferTexture2D ( GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 
                            textureId, 0 );

    //默认读取GL_COLOR_ATTACHMENT0,此处可以不设置
    glReadBuffer ( GL_COLOR_ATTACHMENT0 );

    ///////////////////////////////////////////////////////////////////
    ////////////调用glReadPixels读取现存////////////////////////////////
    ///////////////////////////////////////////////////////////////////
    

    glBindFramebuffer ( GL_FRAMEBUFFER, defaultFramebuffer );

/******* IN Rendering LOOP End  **************/

2. 从GL_TEXTURE_2D_ARRAY中读取:

与1中的实现相同,唯一的区别是在临时FrameBuffer绑定GL_TEXTURE_2D_ARRAY的接口有所区别,需要使用glFramebufferTextureLayer( GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0 );

3. 从帧缓冲区中读取,WindowSurface和PBufferSurface

不需要做特殊操作,直接读取就可以读取eglMakeCurrent时设置的readSurface中的内容。

完整代码如下:

#define FILENAME_MAX 64
#define CAMERA_DUMP_FRM_LOCATION "/sdcard/"
void dumpImage(unsigned char* imagedata,
        uint32_t frameid, uint32_t width, uint32_t height, uint32_t bytesPerPixel) {
    LOG("20191108: %s,%d E .", __FUNCTION__, __LINE__);
    char buf[FILENAME_MAX];
    memset(buf, 0, sizeof(buf));
    snprintf(buf, sizeof(buf), CAMERA_DUMP_FRM_LOCATION "frame_%dX%d_%d.rgb",
             width,height,frameid);
    LOG("20191108: %s,%d buf : %s", __FUNCTION__,__LINE__,buf);
    int file_fd = open(buf, O_RDWR | O_CREAT, 0644);
    uint32_t ImageSize = width*height*bytesPerPixel;
    if (file_fd >= 0)
    {
        ssize_t written_image    = write(file_fd, imagedata, ImageSize);
        LOG("20191108: %s,%d : written number of %zd bytes to file %s", __FUNCTION__, __LINE__, ImageSize, buf);
        close(file_fd);
    }
    else
    {
        LOG("20191108: %s,%d : failed to write data to %s", __FUNCTION__, __LINE__, buf);
    }
    LOG("20191108: %s,%d X .", __FUNCTION__, __LINE__);	
}

GLuint G_Framebuffer = 0;
glGenFramebuffers ( 1, &G_Framebuffer );

/********************* IN Rendering LOOP Begin **************************/

//glDrawBuffer(GL_NONE);
//glReadBuffer(GL_NONE);

//glFramebufferTextureLayer(
//    GL_READ_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,
//    texture,0,0 // Use layer 0 for subsequent operations
//);
GLint defaultFramebuffer = 0;
glGetIntegerv ( GL_FRAMEBUFFER_BINDING, &defaultFramebuffer );

static int frameid = 0;
if((frameid++ % 300) == 0)
{
    glBindFramebuffer ( GL_FRAMEBUFFER, G_Framebuffer );
    glFramebufferTexture2D ( GL_READ_FRAMEBUFFER,
                             GL_COLOR_ATTACHMENT0,
                             GL_TEXTURE_2D,
                             textureId, 0 );
    int width = my_GetIntConfig(TEXTURE_WIDTH);
    int height = my_GetIntConfig(TEXTURE_HEIGHT);
    glReadBuffer ( GL_COLOR_ATTACHMENT0 );
    GLint readType, readFormat;
    GLubyte *pixels;
    glGetIntegerv ( GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType );
    glGetIntegerv ( GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat );
    unsigned int bytesPerPixel = 0;
    switch ( readType )
    {
        case GL_UNSIGNED_BYTE:
        case GL_BYTE:
            switch ( readFormat )
            {
                case GL_RGBA:
                    bytesPerPixel = 4;
                    break;
                case GL_RGB:
                case GL_RGB_INTEGER:
                    bytesPerPixel = 3;
                    break;
                case GL_RG:
                case GL_RG_INTEGER:
                case GL_LUMINANCE_ALPHA:
                    bytesPerPixel = 2;
                    break;
                case GL_RED:
                case GL_RED_INTEGER:
                case GL_ALPHA:
                case GL_LUMINANCE:
                    bytesPerPixel = 1;
                    break;
                default:
                    // Undetected format/error
                    break;
            }
            break;
        case GL_FLOAT:
        case GL_UNSIGNED_INT:
        case GL_INT:
            switch ( readFormat )
            {
                case GL_RGBA:
                case GL_RGBA_INTEGER:
                    bytesPerPixel = 16;
                    break;
                case GL_RGB:
                case GL_RGB_INTEGER:
                    bytesPerPixel = 12;
                    break;
                case GL_RG:
                case GL_RG_INTEGER:
                    bytesPerPixel = 8;
                    break;
                case GL_RED:
                case GL_RED_INTEGER:
                case GL_DEPTH_COMPONENT:
                    bytesPerPixel = 4;
                    break;
                default:
                    // Undetected format/error
                    break;
            }
            break;
        case GL_HALF_FLOAT:
        case GL_UNSIGNED_SHORT:
        case GL_SHORT:
            switch ( readFormat )
            {
                case GL_RGBA:
                case GL_RGBA_INTEGER:
                    bytesPerPixel = 8;
                    break;
                case GL_RGB:
                case GL_RGB_INTEGER:
                    bytesPerPixel = 6;
                    break;
                case GL_RG:
                case GL_RG_INTEGER:
                    bytesPerPixel = 4;
                    break;
                case GL_RED:
                case GL_RED_INTEGER:
                    bytesPerPixel = 2;
                    break;
                default:
                    // Undetected format/error
                    break;
            }
            break;
        case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: // GL_DEPTH_STENCIL
            bytesPerPixel = 8;
            break;
            // GL_RGBA, GL_RGBA_INTEGER format
        case GL_UNSIGNED_INT_2_10_10_10_REV:
        case GL_UNSIGNED_INT_10F_11F_11F_REV: // GL_RGB format
        case GL_UNSIGNED_INT_5_9_9_9_REV: // GL_RGB format
        case GL_UNSIGNED_INT_24_8: // GL_DEPTH_STENCIL format
            bytesPerPixel = 4;
            break;
        case GL_UNSIGNED_SHORT_4_4_4_4: // GL_RGBA format
        case GL_UNSIGNED_SHORT_5_5_5_1: // GL_RGBA format
        case GL_UNSIGNED_SHORT_5_6_5: // GL_RGB format
            bytesPerPixel = 2;
            break;
        default:
            break;
            // Undetected type/error
    }
    pixels = ( GLubyte* ) malloc( width * height * bytesPerPixel );
    glReadPixels ( 0, 0, width, height, readFormat, readType, pixels );
    dumpImage(pixels, frameid, width, height, bytesPerPixel);
}
glBindFramebuffer ( GL_FRAMEBUFFER, defaultFramebuffer );
/********************* IN Rendering LOOP End **************************/	
	
	

 

你可能感兴趣的:(Android)