Home [Android] 동영상에 그림 그리기 (1) - 개요
Post
Cancel

[Android] 동영상에 그림 그리기 (1) - 개요

boomerang

boomerang

이번 포스트부터는 부스트캠프 그룹프로젝트 기간에 개발한 미디어 메모 앱, 특히 제가 구현한 부분인 OpenGL ES 렌더링 방식의 동영상 메모 앱의 구현 과정과 구조에 대해 정리하려고 합니다.

boomerang - 미디어 메모 앱

데모 영상

동영상 메모

사용자에게 보여주기

videoMemo

동영상 메모는 위와 같이 재생되고 있는 동영상 위에 사용자가 그림을 그리는 등 메모를 작성하면 그림이 그려진 동영상이 저장되고, 이를 공유할 수 있는 기능입니다.

이 기능을 세가지로 나누어서 생각해보면

  1. 동영상을 보여주기
  2. 동영상에 그림을 그리기
  3. 그려진 동영상을 저장

이렇게 나눌 수 있을 것입니다.

그런데 이 방법을 순서대로 따라가면 한 가지 문제점이 있습니다. 동영상을 재생하면서 사용자에게 보여주면, 그려진 그림은 어떻게 보여줄 수 있을까요? 이미 원본 동영상은 재생되고 있고, 거기에 그림을 그려 저장한다면 그림이 그려진 동영상은 저장되지만 그 그림을 사용자가 바로 확인할 수가 없습니다.

즉, 사용자는 자신이 어떤 그림을 그리는지 확인하지 못한다는 것입니다! 그리고 있는 그림을 저장이 되고 나서야 확인할 수 있다면, 아무래도 썩 좋은 사용자 경험은 아닐 것 같습니다.

그래서 순서를 바꿔서 생각하였습니다.

  1. 동영상에 그림을 그리기
  2. 동영상을 보여주기
  3. 그려진 동영상을 저장

이 방법에서 고민할 점은 어떤 동영상에 그림을 그려야 하는지 1번에서 어떻게 알 수 있을까요? 우선 그림을 그리기 전에 그릴 대상이 존재해야 할 것입니다. 그래서 처음에 과정을 하나 더하였습니다.

  1. 동영상을 재생하기 (사용자에게 보여지지는 않음!)
  2. 동영상에 그림을 그리기
  3. 동영상을 보여주기
  4. 그려진 동영상을 저장

이렇게 한다면 우선 동영상을 재생하고, 그곳에 그림을 그린 후 그 결과를 사용자에게 보여주게 될 것입니다. 그리고 그 동영상을 저장합니다.

동영상에 그림 그리기

그렇다면 동영상에 그림을 어떻게 그릴 수 있을까요? 처음에 떠오른 두 가지 방법이 있습니다.

  1. 동영상을 재생시키고 그 위에 Canvas로 그림을 그리기
  2. 프레임 단위로 나누어서 각 프레임마다 그림을 그리고 다시 합치기

첫 번째 방법이 더 찾기 쉬워보입니다. 하지만 그렇다면 어떻게 저장을 할 수 있을까요? 물론 MediaProjection 클래스를 사용하여 화면 전체를 녹화할 수 있습니다. 하지만 이 클래스는 SurfaceFlinger까지 거치고 난 뒤의 사용자에게 표시되는 화면 그 자체를 녹화해 상태바를 포함한 모든 UI가 녹화되는 기능입니다. 이렇게 한 뒤 동영상 부분만 잘라서도 저장할 수 있을 것 같지만, 더 좋은 방법이 있을 것 같아 두 번째 방법도 생각해보았습니다.

두 번째 방법은 동영상을 프레임 단위로 나누어 하나씩 그림을 그리고 다시 합쳐서 동영상으로 만들어 저장하는 것입니다. 이 방법을 사용하는 것은 꽤 어려워 보였습니다. 자료가 많지 않아서 어떻게 접근해야 하는지조차 알기 어려웠습니다.

저는 AOSP 그래픽 문서, Google에서 Android 프레임워크의 그래픽 관련 기능들을 구현한 프로젝트 Grafika에서 큰 도움을 얻을 수 있었습니다.

자세한 내용은 이후 포스트에서 다루겠지만 간단히 정리하자면 이미지 스트림 생성자는 이미지 스트림 소비자에게 표시할 이미지의 버퍼를 Surface라는 클래스를 통해 전달할 수 있습니다.

동영상을 재생하는 MediaPlayer도 이미지 스트림 생성자 중 하나입니다. 이미지 스트림 소비자는 일반적으로 화면에 표시될 UI들을 합성하는 SurfaceFlinger지만 우리는 바로 사용자에게 보여주지 않고 그림을 그린 뒤에 보여주기로 하였습니다. 그렇다면 다른 이미지 스트림 소비자에 연결되어야 할 것입니다.

OpenGL ES를 사용하는 클래스들도 이미지 스트림 소비자가 될 수 있습니다. OpenGL ES는 그래픽 렌더링 라이브러리로, Canvas와 같은 다른 안드로이드 프레임워크와 다르게 하드웨어 가속 렌더링을 수행할 수 있어 성능에 큰 장점을 가지고 있습니다.

그래서 MediaPlayer를 OpenGL ES 렌더링을 수행할 수 있는 SurfaceTexture 클래스와 연결시켰습니다. 그리고 SurfaceTexture에서는 프레임에 그림을 더하고, 그 결과를 화면에 표시하고 다시 동영상으로 저장할 수 있을 것입니다.

정리

intro

위 내용들을 간단히 정리하면 위 그림처럼 나타낼 수 있습니다. 위에서 언급하지 못한 내용이 많지만 내용이 너무 길어져 하나씩 따로 작성하겠습니다.

여기까지가 동영상 메모의 기본적인 아이디어였습니다. 다음 포스트부터는 각 과정에 대해 자세히 다뤄보도록 하겠습니다.

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

부스트캠프 웹·모바일 6기 수료 후기

[Android] 동영상에 그림 그리기 (2) - Surface