Home [Android] 동영상에 그림 그리기 (9) - SurfaceView로 화면 표시
Post
Cancel

[Android] 동영상에 그림 그리기 (9) - SurfaceView로 화면 표시

지난 포스트에서는 MediaCodec에서 생성한 Surface에 비디오 버퍼를 전달하여 동영상을 저장하였습니다. 이번 포스트에서는 동영상을 사용자에게 표시하는 방법에 대해 작성하겠습니다.

SurfaceView

사용자는 스스로가 그리고 있는 그림을 계속 확인하여야 하기 때문에, 화면에 표시될 것은 원본 동영상이 아닌 그림이 그려진 동영상의 각 이미지 프레임입니다. 지난 포스트에서 그림이 그려진 그래픽 버퍼를 어떻게 SurfaceView의 Surface로 전달하는지에 대해서 작성하였습니다.

SurfaceView를 이름과 연관지어 설명하자면 Surface+View로, 뷰 계층구조 내에 추가적인 Surface를 생성하고자 할 때 사용할 수 있습니다.

뷰 계층구조 내에 추가적인 Surface가 필요할 때는 언제일까요? 지난 포스트에서 SurfaceFlinger의 각 Layer는 각각의 BufferQueue를 가지고, 이 BufferQueue의 생산자 측에 Surface를 전달하여 그래픽 버퍼를 가져온다고 하였습니다.

각 BufferQueue마다 따로 그래픽 버퍼를 전달할 수 있기 때문에, 그래픽 버퍼를 자주 갱신해야 한다면 별개의 Surface를 가져 뷰 계층구조 전체의 그래픽 버퍼를 전달하는 대신 필요한 부분만 전달할 수 있을 것입니다.

SurfaceView를 생성하면 SurfaceControl에게 새로운 Surface의 생성을 요청합니다. 그러면 SurfaceFlinger에서 새로운 BufferQueue를 생성하고, Surface를 전달할 것입니다. SurfaceFlinger로부터 전달받은 Surface들을 사용하기 위해서는 SurfaceHolder 인터페이스를 사용하면 됩니다(이 내용은 지난 포스트에서 작성하였습니다.)

이렇게 가져온 Surface는 여러 생산자 API에서 사용될 수 있습니다. 대표적인 예로 이 앱에서 사용한 OpenGL ES이나 카메라 미리보기, MediaPlayer 등이 있습니다.

TextureView

SurfaceView와 비교할 대상으로 TextureView가 있습니다.

SurfaceView와 TextureView 둘 모두가 뷰 계층구조의 일부라는 공통점이 있지만, 실제 구현에 있어서는 큰 차이가 있습니다.

TextureView는 SurfaceTexture를 생성할 수 있고, Surface를 생산자에게 전달하여 원하는 그래픽 버퍼를 가져올 수 있습니다. 즉 TextureView의 그래픽을 그리거나 갱신할 때 Surface에 하드웨어 가속을 적용해 그릴 수도 있고, SurfaceTexture를 이용해 OpenGL ES로도 렌더링하는 등 기존 방식보다 성능상의 이점을 가질 수 있습니다.

하지만 Surface가 SurfaceView처럼 분리되지 않기 때문에 SurfaceView가 성능에서 더 우위를 가집니다. 뷰의 일부에서 동영상을 재생한다고 가정할 때, SurfaceView를 사용하면 동영상을 재생하는 부분만 별도의 Surface로 분리하여 해당부분의 그래픽 버퍼만 갱신할 수 있습니다. 하지만 TextureView는 Surface가 분리되지 않기 때문에 갱신시에 뷰 계층구조의 다른 컴포넌트들도 함께 갱신되고, 이는 성능 저하의 원인이 될 것입니다.

API 24 이전에는 SurfaceView의 분리된 Surface가 예상대로 동기화되지 않는 문제점이 발생하였지만 현재는 수정되었기 때문에 꼭 필요한 경우가 아니라면, SurfaceView의 사용을 권장합니다.

This post is licensed under CC BY 4.0 by the author.

[Android] 동영상에 그림 그리기 (8) - BufferQueue, WindowManager, SurfaceFlinger

[Android] 동영상에 그림 그리기 (10) - 개선 리스트