2013-12-16 4 views
2

gldsurfaceview의 출력을 sdCard의 PNG로 렌더링하려고하는데 문제가 있습니다. 비슷한 며칠을 정렬하려고 며칠을 보냈는데 이것은 내 수준의 전문성을 뛰어 넘었습니다. 누군가가 나를 아래의 로그를 통해 정렬 도와 줄 수 있고 내가 잘못 될 수도 있습니다 볼 수 있습니다.GLSURFACEVIEW에서 PNG로 저장 - 오류 glReadPixels

감사합니다.

로그 :

12-16 12:09:18.831: E/AndroidRuntime(29864): FATAL EXCEPTION: GLThread 2712 
12-16 12:09:18.831: E/AndroidRuntime(29864): java.nio.BufferUnderflowException 
12-16 12:09:18.831: E/AndroidRuntime(29864): at java.nio.Buffer.checkGetBounds(Buffer.java:177) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:66) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at java.nio.IntToByteBufferAdapter.get(IntToByteBufferAdapter.java:105) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at java.nio.IntBuffer.get(IntBuffer.java:234) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at com.research.glgrade.GLLayer.grabPixels(GLLayer.java:865) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at com.research.glgrade.GLLayer.saveScreenShot(GLLayer.java:810) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at com.research.glgrade.GLLayer.onDrawFrame(GLLayer.java:794) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1527) 
12-16 12:09:18.831: E/AndroidRuntime(29864): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240) 
12-16 12:09:26.849: I/Choreographer(29864): Skipped 478 frames! The application may be doing too much work on its main thread. 

여기에 내 현재 코드 : 주요 활동에서 :

GlobalVariables.setPrint("true"); 
mView.requestRender(); 

가에서 렌더링 클래스

public void onDrawFrame(GL10 glUnused) { 
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 
    final String vertexShader = getVertexShader(); 
    final String fragmentShader = getFragmentShader(); 

    final int vertexShaderHandle = ShaderHelper.compileShader(
      GLES20.GL_VERTEX_SHADER, vertexShader); 
    final int fragmentShaderHandle = ShaderHelper.compileShader(
      GLES20.GL_FRAGMENT_SHADER, fragmentShader); 

    mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, 
      fragmentShaderHandle, new String[] { "a_Position", 
        "a_TexCoordinate" }); 

    // Set our per-vertex lighting program. 
    GLES20.glUseProgram(mProgramHandle); 
      // Set program handles for cube drawing. 
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, 
      "u_MVPMatrix"); 
    mTextureUniformHandle0 = GLES20.glGetUniformLocation(mProgramHandle, 
      "u_Texture0"); 
    mTextureUniformHandle1 = GLES20.glGetUniformLocation(mProgramHandle, 
      "u_Texture1"); 

      GLES20.glActiveTexture(GLES20.GL_TEXTURE4); 
      // Bind the texture to this unit. 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle4); 
      // Tell the texture uniform sampler to use this texture in the shader by 
      // binding to texture unit 3. 
    GLES20.glUniform1i(mTextureUniformHandle4, 4); 


    // Draw some cubes. 
    Matrix.setIdentityM(mModelMatrix, 0); 


    Matrix.translateM(mModelMatrix, 0, mTransX, mTransY, mAngle*0.05f); 
    Matrix.rotateM(mModelMatrix, 0, 0.0f, 1.0f, 1.0f, 0.0f); 
    drawCube(); 


    int width_surfacea = width_surface ; 
     int height_surfacea = height_surface ; 

    if (GlobalVariables.getPrint() != "false") { 

     String mFrameCount = "1"; 
     saveScreenShot(0, 0, width_surfacea, height_surfacea, "/save/test.png"); 
     GlobalVariables.setPrint("false"); 


    } 

} 

    public void saveScreenShot(int x, int y, int w, int h, String filename) { 

    Bitmap bmp = grabPixels(x, y, w, h); 

    try { 
     String path = Environment.getExternalStorageDirectory() + "/" + filename; 

     File file = new File(path); 
     file.createNewFile(); 

     FileOutputStream fos = new FileOutputStream(file); 
     bmp.compress(CompressFormat.PNG, 100, fos); 

     fos.flush(); 

     fos.close(); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public Bitmap grabPixels(int x, int y, int w, int h) { 

    int screenshotSize = w * h; 

    ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 3); 
    bb.order(ByteOrder.nativeOrder()); 
    bb.position(0); 
    GLES20.glReadPixels(0, 0, w, h, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, bb); 
    int pixelsBuffer[] = new int[screenshotSize]; 

    bb.asIntBuffer().get(pixelsBuffer); 
    bb = null; 

    Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); 

    bitmap.setPixels(pixelsBuffer, screenshotSize-w, -w, 0, 0, w, h); 

    pixelsBuffer = null; 

    short sBuffer[] = new short[screenshotSize]; 
    ShortBuffer sb = ShortBuffer.wrap(sBuffer); 
    bitmap.copyPixelsToBuffer(sb); 

    //Making created bitmap (from OpenGL points) compatible with Android bitmap 
    for (int i = 0; i < screenshotSize; ++i) {     
     short v = sBuffer[i]; 
     sBuffer[i] = (short) (((v&0x1f) << 11) | (v&0x7e0) | ((v&0xf800) >> 11)); 
    } 
    sb.rewind(); 
    bitmap.copyPixelsFromBuffer(sb); 


    return bitmap; 

} 
+0

GL 컨텍스트를 선택한 경우 어떤 픽셀 형식을 선택하셨습니까? –

+0

내 주요 활동 onCreate에서 mView를 mView.setZOrderOnTop (false)로 정의합니다. mView.setEGLContextClientVersion (2); mView.setRenderer (새 GLLayer (this)); mView.setDebugFlags (GLSurfaceView.DEBUG_CHECK_GL_ERROR); //mView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); mView.setRenderMode (GLSurfaceView.RENDERMODE_CONTINUOUSLY); – user1540142

+0

GLSurfaceview에 대한 특정 Color 정의가 없습니다. – user1540142

답변

2

배열 길이가 일치하지 않습니다. 코드 라인은 : bb.asIntBuffer()의 길이는 단지 때문에

bb.asIntBuffer().get(pixelsBuffer); 

는 예외가 발생 pixelsBuffer의 길이는 물론 (* H는 * 4 승 동안 (* h를 승 * 3) 나는 바이트에 관해 말하기). 그것은 (워드 프로세서에 따라)해야으로 그래서 가져 오기는()에서 예외가 발생 http://developer.android.com/reference/java/nio/IntBuffer.html#get%28int[]%29

업데이트 :

은 (경고 : 나는 심지어 그것을 컴파일하려고하지 않은) :이 코드를 시도

public Bitmap grabPixels(int x, int y, int w, int h) { 

    // Allocate byte array of H*W size assuming that we retrieve only R,G and B values 
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(screenshotSize * 3); 
    byteBuffer.order(ByteOrder.nativeOrder()); 
    byteBuffer.position(0); 
    // Read RGB values to our byte array 
    GLES20.glReadPixels(x, y, w, h, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, byteBuffer); 

    //Now we need to convert the 24bit RGB data to ARGB8888 format 
    // I like arrays, they are honest :) 
    byte[] pixelBuffer = byteBuffer.array(); 
    // This is an array that we going to use as backend for the bitmap 
    int[] finalPixels = new int[w*h]; 
    // Let the magic flow 
    int j = 0; 
    for (int i = 0; i < pixelBuffer.length; i += 3) { 
     byte red = pixelBuffer[i]; 
     byte green = pixelBuffer[i+1]; 
     byte blue = pixelBuffer[i+2]; 

     finalPixels[j++] = 0xFF000000 | ((int)blue << 16) | ((int)green << 8) | red; 
    } 

    // Create a bitmap of ARGB_8888 
    return Bitmap.createBitmap(finalPixels, w, h, Bitmap.Config.ARGB_8888); 
} 
+0

감사합니다. Alex. bb를 BYteBuffer.allocateDirect (screenshotSize * 4)로 변경했습니다. 이제 충돌없이 프로세스가 실행되지만 결과 PNG는 BLACK입니다. – user1540142

+0

안녕하세요 알렉스 내가 변경 사항을 추가하고 코드가 원활하게 실행되지만 결과 이미지는 여전히 검은 색입니다. glReadPixels 접두사 GLES20 있기 때문에 때문입니까? ReadPixels에 내 화면 이미지가 있는지 여부를 확인하려면 어떻게해야합니까? – user1540142

+0

이것은 EGLConfigChooser를 8888과 일치시킨 후에 작동했습니다. – user1540142

1

내가 ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 3); 잘못 생각합니다. ByteBuffer bb = ByteBuffer.allocateDirect(screenshotSize * 4);

+0

Thanks Shashika. * 4로 변경하면 충돌없이 PNG가 저장되지만 BLACK입니다. – user1540142

+0

두 가지 추가 변경 사항을 제안합니다. GLES20.glReadPixels (0, 0, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, bb); 및 비트 맵 비트 맵 = 비트 맵.createBitmap (w, h, Bitmap.Config.ARGB_8888); – Shashika

+0

뭔가 잘못되었습니다. 두 가지를 모두 변경하면 "스택 손상이 중단되었습니다"라는 메시지가 나타납니다. 당신의 도움을 주셔서 감사합니다. – user1540142

2

MPEG 파일에서 프레임을 추출하는 샘플 코드는 on bigflake입니다. 비디오 프레임은 GL로 렌더링되고 saveFrame() 함수는 glReadPixels()Bitmap을 사용하여 PNG로 디스크에 저장합니다.

주의해야 할 중요한 성능상의 함정이 있습니다. saveFrame()의 주석을 참조하여 NIO를 가장 효과적으로 사용하는 방법에 대한 정보를 얻으십시오. 또한 EGLConfig가 픽셀 읽기 형식과 일치하는지 확인해야합니다 (소스 및 대상 형식이 동일하지 않으면 glReadPixels()이 매우 느려질 수 있음).

업데이트 : Grafika에서 좀 더 일반적인 구현이 있습니다. EglSurfaceBase#saveFrame()을 참조하십시오.