2015-02-05 4 views
1

Google의 Grafika repo에 의존하는 라이브 스트리밍 API를 사용하고 있습니다. Grafika EGLSurfaceBase의 saveFrame 메서드를 사용하여 사용자가 스트리밍하는 동안 비디오의 정지 영상을 캡처 할 수 있습니다.Android에서 비트 맵을 만들기 전에 Bytebuffer에서 OpenGL 텍스처를 뒤집기

https://github.com/google/grafika/blob/master/src/com/android/grafika/gles/EglSurfaceBase.java

실제 캡처 작동하지만 분명히 일부 카메라 방향의 이미지는 이성을 상실한다.

나는 OpenGL을 텍스처에서 가져온 거꾸로 비트 맵에 관한 질문을 많이 발견했습니다 -하지만 대부분의 중 하나에 그려진 이미지를 참조 할 것 같고 의존 :

A) OpenG의 질감을 틀지. 하지만 제 경우에는 라이브 스트리밍 API를 사용하여 이미지를 캡처하기 위해 텍스처를 뒤집어 실제로 비디오 스트림에서 이미지 캡처를 뒤집을 수 있습니다. 이 자원에 기초하여 생성 된 후 비트 맵을 내리고

OR

b). 필자는 리소스가 없으며 바이트 버퍼에서 비트 맵을 생성하고 그것을 복제하기 위해 복제하지 않을 것입니다.

 String filename = file.toString(); 

    int width = getWidth(); 
    int height = getHeight(); 
    ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); 
    buf.order(ByteOrder.LITTLE_ENDIAN); 
    GLES20.glReadPixels(0, 0, width, height, 
      GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf); 
    GlUtil.checkGlError("glReadPixels"); 
    buf.rewind(); 

    BufferedOutputStream bos = null; 
    try { 
     bos = new BufferedOutputStream(new FileOutputStream(filename)); 
     Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
     bmp.copyPixelsFromBuffer(buf); 
     bmp.compress(Bitmap.CompressFormat.PNG, 90, bos); 
     bmp.recycle(); 
    } finally { 
     if (bos != null) bos.close(); 
    } 
    Log.d(TAG, "Saved " + width + "x" + height + " frame as '" + filename + "'"); 
} 

내 선호하는 솔루션은 사전에 이미지를 뒤집을 수있는 방법을 찾아야하는 것입니다 : 나는 그것을 카메라 방향을 전달되지만 제 질문은 - 여기

는 API가 가지고있는 기본 EGLSurfaceBase 방법입니다 BMP.createbitmap (또는 동시에). 예를 들어 행렬을 사용하여 픽셀 읽기를 glReadPixels로 바꿀 수 있습니까?

또 다른 메모/생각 : 비트 맵을 만든 후 비트 맵을 전환하는 비용은 사용자 상호 작용에 의존하기 때문에 메모리 오류가 발생하기에 충분하지 않을 수 있기 때문에 간단합니다.

답변

2

OpenGL 제시 버퍼의 첫 번째 픽셀이 왼쪽 하단에 있기 때문에 이미지가 항상 읽혀진 것처럼 보입니다. 올바른 순서를 얻는 방법에는 두 가지가 있습니다.

하나는 버퍼에 거꾸로 뒤집어서 별도의 버퍼에서 수행 할 수 있으며 현재 드로잉 파이프 라인을 전혀 방해하지 않습니다. 별도의 스레드에서 작업하거나 이미지의 크기를 조정하려는 경우 실제로는 꽤 좋은 아이디어 일 수 있습니다. 이것은 모두 하나의 드로 콜에서 수행 할 수 있습니다.

다른 것은 수동으로 데이터를 뒤집는 것입니다. 실제로는 열을 뒤집을 필요가 있기 때문에 나쁘지는 않습니다 (열은 꽤 나쁠 것입니다). 어쨌든 실제로 동일한 버퍼에서이 작업을 수행 할 수 있습니다. 버퍼 복사본이 필요하지 않습니다. 다음과 같은 순서로 줄을 바꾸기 만하면됩니다. 첫 번째 줄을 저장하고 마지막 줄로 바꾸고 마지막 줄을 저장된 줄로 바꾸고 두 번째 줄을 계속하십시오.

+0

덕분에 도움을 많이 :

확인하는 구현입니다. 나는 OpenGL 문서와 OpenGL ES의 특이성 사이에서 OpenGL을 완전히 잃어 버렸음을 인정해야한다. 옵션 1 (버퍼를 뒤집어서 그립니다)에서 어떻게 시작합니까? 참조할만한 링크 또는 몇 줄의 코드 만 있으면 Google에서 코드를 다시 읽는 데 도움이됩니다. – Laurent

+0

당신의 대답이 올 때까지 나의 해결책을 깨워라. 비트 맵 # 2를 만들고 (데이터를 디스크에 저장하기 전에) 변환 매트릭스로 첫 번째 비트 맵을 복사해라. 이것은 성능에 많은 영향을 미치지 않았지만 메모리 할당보다는 시간에 집중했습니다. – Laurent

+0

사실 이것은 매우 간단합니다. 당신이해야 할 일은 새로운 프레임 버퍼와 렌더 버퍼를 생성하고 메인 버퍼에서했던 것처럼 첨부하는 것입니다. 그런 다음 프레임 버퍼를 바인딩 한 후 올바른 뷰포트를 설정하면 메인 버퍼에서했던 것처럼 드로잉 코드를 호출 할 수 있습니다. 유일한 차이점은 정사 (ortho) 또는 절두체 (frustum) 매트릭스에서 상단과 하단을 뒤집을 수 있다는 것입니다. 완료되면 이전 프레임 버퍼를 바인드하여 계속 진행하십시오. FBO에 그림을 그리기위한 자세한 검색을하거나 새로운 질문을 호소합니다. –

2

glReadPixels 뒤에 ByteBuffer를 뒤집을 수 있습니다. 메모리 복사본이기 때문에 매우 빠릅니다. 내 테스트는 역 동작이 10ms 미만이라는 것을 보여주었습니다.

private void reverseBuf(ByteBuffer buf, int width, int height) 
{ 
    long ts = System.currentTimeMillis(); 
    int i = 0; 
    byte[] tmp = new byte[width * 4]; 
    while (i++ < height/2) 
    { 
     buf.get(tmp); 
     System.arraycopy(buf.array(), buf.limit() - buf.position(), buf.array(), buf.position() - width * 4, width * 4); 
     System.arraycopy(tmp, 0, buf.array(), buf.limit() - buf.position(), width * 4); 
    } 
    buf.rewind(); 
    Log.d(TAG, "reverseBuf took " + (System.currentTimeMillis() - ts) + "ms"); 
} 
+0

감사합니다, 사랑하는 잠자리! 이 코드는 YoWindow 날씨 앱에서 공유 화면을 내보내는 데 사용됩니다. – Pavel

관련 문제