2013-05-06 3 views
7

안드로이드에서 카메라 프레임에 대해 OpenGL 처리를 수행하고 카메라 미리보기에서 해당 프레임을 표시 한 다음 프레임을 비디오 파일로 인코딩하려고합니다. OpenGL을 사용하여 GLSurfaceView 및 GLSurfaceView.Renderer를 사용하고 비디오 인코딩을 위해 FFMPEG를 사용하여이 작업을 수행하려고합니다.안드로이드에서 Pixel Buffer Objects (PBO) 사용하기

쉐이더를 사용하여 이미지 프레임을 성공적으로 처리했습니다. 이제 처리 된 프레임을 비디오로 인코딩해야합니다. GLSurfaceView.Renderer는 onDrawFrame (GL10 ..) 메소드를 제공합니다. 이 메소드에서는 glReadPixels()를 사용하여 이미지 프레임을 읽은 다음 프레임을 비디오 인코딩으로 큐에 배치하려고합니다. 자체적으로 glReadPixels()가 너무 느려서 - 프레임 속도가 한 자리 숫자입니다. Pixel Buffer Objects를 사용하여 속도를 높이려고합니다. 이것은 작동하지 않습니다. pbo를 연결하면 프레임 속도가 변경되지 않습니다. OpenGL을 처음 사용하는 것이므로 문제를 어디서부터 시작해야할지 모르겠습니다. 이 일을 제대로하고 있습니까? 아무도 내게 어떤 방향을 줄 수 있습니까? 미리 감사드립니다.

public class MainRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { 

. 
. 

    public void onDrawFrame (GL10 gl10) { 

     //Create a buffer to hold the image frame  
     ByteBuffer byte_buffer = ByteBuffer.allocateDirect(this.width * this.height * 4); 
     byte_buffer.order(ByteOrder.nativeOrder()); 

     //Generate a pointer to the frame buffers 
     IntBuffer image_buffers = IntBuffer.allocate(1); 
     GLES20.glGenBuffers(1, image_buffers); 

     //Create the buffer 
     GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, image_buffers.get(0)); 
     GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, byte_buffer.limit(), byte_buffer, GLES20.GL_STATIC_DRAW); 
     GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, image_buffers.get(0)); 

     //Read the pixel data into the buffer 
     gl10.glReadPixels(0, 0, this.width, this.height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, byte_buffer); 

     //encode the frame to video 
     enQueueForEncoding(byte_buffer); 

     //unbind the buffer 
     GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 
    } 

. 
. 

} 
+0

Google Grafika 예제를 확인하셨습니까? OpenGL 구현이 Android에서 도달 할 수있는 최적의 상태에 가까워지면 너무 놀라지 않을 것입니다. 즉, https://github.com/google/grafika/blob/master/src/com/android/grafika/RecordFBOActivity.java – harism

+0

glReadPixels 호출의 경우 glReadPixels (0, 0, width, height, format, GL_UNSIGNED_BYTE, 0); 마지막에 0이 전달되지만 java가 null을 허용하지 않으므로 JNI를 통해이 작업을 수행해야합니다. 평소처럼 맵 버퍼를 사용합니다. –

답변

0

전 (opengl + video enconding) 전에 그런 시도를 해 본 적이 없지만 기기 메모리에서 읽는 것이 천천히한다는 것을 알 수 있습니다. 이중 버퍼링을 시도하면 DMA 컨트롤러가 물건을 다시 읽는 동안 GPU가 두 번째 버퍼로 렌더링을 유지할 수 있으므로 도움이됩니다.

프로파일 러를로드하고 (장치의 GPU 공급 업체를 확인하십시오.) 몇 가지 아이디어를 얻을 수 있습니다. 또 다른 도움은 내부 pbuffer 형식을 다른 것으로 설정하고, 더 낮은 숫자를 시도하고 채널 (알파)을 삭제하는 것입니다.

편집 : 당신이 그런 느낌이 들면, GPU에서 비디오를 인코딩 할 수 있습니다. 그러면 비디오, 메모리 및 프로세싱이 현명하게 향상 될 것입니다.

+0

TraxNet, 답장을 보내 주셔서 감사합니다. 알파 채널을 잃어 버리려고 노력할 것입니다. 나는 그것이 도움이 될 것이라고 확신하지만 큰 차이를 만들지는 않을 것입니다. GPU에서의 인코딩은 공급 업체마다 다를 수 있습니다. 다른 장치에서 실행해야합니다. –

+0

그는 아마도 GPU 부작용을 위해 RenderScript를 사용한다는 것을 의미합니다. 그것은 벤더 독립적입니다. – akauppi

1

glBufferData()이 내부 버퍼를 GPU 메모리에 매핑하지 않는다는 것을 기억하기 때문에 메모리의 데이터를 버퍼로 복사 (초기화)합니다.

glBufferData()에 의해 할당 된 메모리에 액세스하려면 glMapBufferRange()을 사용해야합니다. 이 함수는 읽을 수있는 Java Buffer 객체를 반환합니다.

관련 문제