부드러운 둥영상 탐색
수정
수정된 블로그 글을 여기서 찾아보실 수 있습니다.
둥영상을 재생할 때 어떤 둥영상 파일들은 재생 프로그렘에서 “탐색"이 부드럽게 되는 것을 눈치챘을 때가 있을 겁니다. 그러니까, “탐색"을 하기 위해 재생 위치 “헤드"를 좌우로 움직일 때, 끊김이나 별다른 “렉” 없이 프레임이 화면에 바로 표시되는 것 말입니다 (물론 재생하는 장치가 그만큼 빨리 재생할 수 있을 경우일 때를 가정합니다.)
플레이어가 프레임 단위로 탐색하는 것뿐만 아니라, 어떤 둥영상들은 뒤로 탐색하는 것까지 허용합니다. 다시보기 같은 것을 분석하거나 둥영상에서 특정 부분을 찾을 매우 유용합니다.
이 글에서는 왜 어떤 둥영상들이 이렇게 탐색이 간편한지 설명하고, 어떻게 둥영상을 재인코딩하여 탐색을 부드럽게 할 수 있는지 설명하겠습니다!
둥영상 인코딩과 디코딩에 대한 간단한 정리
참고: 아래의 내용은 둥영상 인코더와 디코더가 어떻게 작동하는지를 간단하게 요약한 버전입니다. 이 블로그 글을 위해선 완전히 이해할 필요가 없지만 그래도 키프레임 (keyframe) 타입이 무엇인지 이해해야 다음 부분이 설명이 됩니다. 만약 전문가분께서 이 글을 읽으면서 너무 단순화되어 있다고 느끼신다면 죄송합니다!
아시다시피, 둥영상 파일들은 단순한 컨테이너로, 한 개 또는 여러 개의 둥영상 “스트림” (stream), 한 개 또는 여러 개의 오디오 스트림, 그리고 다른 스트림 타입(예를 들어 자막 등)을 담고 있는 컨테이너입니다. 일단 오디오 스트림과 다른 스트림 타입은 중요하지 않으니 잠시 무시하겠습니다. 여기에서 집중해야 할 부분은 둥영상 스트림입니다.
둥영상 스트림은 그냥 연속된 사진의 집합입니다. 하지만 사진들을 그대로 한 프레임씩 저장하는 것은 낭비가 꽤 심합니다. 다음과 같이 계산해보겠습니다!
- 한 픽셀은 빨간색, 초록색, 그리고 파란색 (RGB) 값으로 이루어져 있고, 각 값은 0에서 255까지의 범위 내에 있습니다 (이때 둥영상 색상이 8비트라고 가정하겠습니다).
- 그러면 한 색상 당 8비트의 정보가 필요한데, 8비트는 1바이트이니 한 픽셀 당 3바이트의 값을 저장해야 됩니다.
- 일반적인 1080p 둥영상 파일을 위해 1920 * 1080개의 픽셀을 저장해야 합니다. 1920 * 1080 = 2,073,600. 각 픽셀을 3바이트이니 한 프레임 당 6,220,800 바이트를 저장해야 됩니다. (약 6,221킬로바이트, 또는 6.2메가바이트의 데이타죠.)
- 둥영상 파일이 1초당 24 프레임을 가지고 있다고 가정하겠습니다 (영화 등의 파일에서 흔한 값입니다). 6,220,800 * 24 = 149,299,200바이트, 또는 149,299킬로바이트, 또는 149메가바이트를 차지합니다. 1초밖에 안 되는 둥영상을 위해서 말이죠!
- 약 30초 정도의 짧은 둥영상 파일이라고 가정해보겠습니다. 149,299,200 * 30 = 4,478,976,000바이트, 또는 4,478,976킬로바이트, 또는 4,479메가바이트, 또는 4.4기가바이트를 차지합니다.
- 60초로 늘려보겠습니다. 149,299,200 * 60 = 8,957,952,000바이트 = 8,957,952킬로바이트 = 8,958메가바이트 = 9기가바이트를 차지하게 됩니다!
- 2시간짜리 영화면 어떨까요? 149,299,200 * 60 * 60 * 2 = 1,074,954,240,000바이트 = 1,074,952,240킬로바이트 = 1,074,952메가바이트 = 1,075기가바이트 = 1 테라바이트를 차지합니다.
당연하게도, 그 정도의 데이터를 저장하고 싶지는 않겠죠. 그래서 둥영상 인코더와 디코더가 필요한 겁니다.
둥영상 스트림들은 여러가지 기준을 기반으로 인코딩되고 디코딩됩니다. 주로 사용되는 것이 H264이고, 그리고 그 뒤를 이어 표준이 되기 위해 경쟁하는 H265와 AV1 기준들이 있습니다. (물론, 다른 기준들도 여럿 존재합니다.) 둥영상 인코더의 역할은 둥영상의 프레임을 바탕으로 “키프레임”이라는 것을 생성하는 것입니다. 여기에서 키프레임은 세 가지 종류가 있는데, I-프레임, P-프레임, 그리고 B-프레임이 존재합니다.
I-프레임은 예전에 설명했던 프레임 그대로입니다. 둥영상 프레임 하나를 구성하는 데이터 전부를 가지고 있습니다.
P-프레임은 I-프레임을 참조합니다. 거의 대부분의 둥영상들은 패턴을 가지고 있는데 (예를 들어, 정적인 배경 앞에 동적인 사물/인물 등), 이 경우에는 둥영상 인코더가 장면을 모두 담고 있는 I-프레임을 만든 다음, ”둥영상 속 사물/인물이 오른쪽으로 2,000픽셀, 위로 400픽셀 움직였어“라는 내용의 P-프레임을 생성합니다. 그러면 디코더가 그 정보를 바탕으로 I-프레임 위에 바뀐 부분만을 다시 그리게 됩니다.
B-프레임들은 앞과 뒤의 프레임을 모두 참조합니다. 가장 공간을 많이 절약하지만, 인코딩하고 디코딩하는데 부하가 가장 많이 필요합니다.
그래서 위에 매우 간략하고 전반적인 둥영상 인코딩/디코딩 과정을 담았습니다. 그러면 이게 어떻게 둥영상 탐색에 영향을 미칠까요?
키프레임과 둥영상 탐색
둥영상에서 앞과 뒤로 탐색하게 될 경우, 플레이어는 먼저 플레이헤드(탐색 위치 막대)에 가장 인접한 I-프레임을 찾아야 됩니다. 그 다음, I-프레임 위에 P-프레임과 B-프레임을 쌓아 원하는 장면까지 탐색하게 됩니다. (어떤 플레이어들은 그냥 이 과정을 다 무시하고 강제로 인접한 I-프레임으로 탐색합니다. 만약 플레이헤드가 놓은 위치에서 앞/뒤로 점프하는 것을 보셨다면 이를 경험한 것일 수도 있습니다.)
이는 P-프레임과 B-프레임이 부분적인 프레임이기 때문입니다. 프레임 전의 I-프레임이 어떻게 바뀌었는지 설명하는 프레임에 불과하기 때문에, 그냥 그대로 표시할 수 없습니다. (전의 예시처럼, 만약 I-프레임이 ”파란색 하늘 배경에 하얀색 구름 앞 초록색 드레스를 입고 있는 사람을 그려“라는 명령을 담고 있다고 가정한다면, P와 B-프레임들은 ”초록색 드레스가 오른쪽으로 200픽셀 움직였어“와 같은 명령에 불과하기 때문입니다. 사람도 I-프레임의 명령 없이 P와 B-프레임의 명령을 정확히 그릴 수 없고, 컴퓨터도 마찬가지입니다.)
기기들은 (적어도 최신 기기들은) I-프레임과 P-프레임을 비교적 빨리 디코딩할 수 있습니다. 따라서 둥영상이 I와 P-프레임으로만 이루어져 있다면, 탐색이 부드러울 것입니다. 하지만 B-프레임들은 더 많은 시간과 계산이 필요하기 때문에, 재생 막대를 빨리 탐색할 경우 기기들이 느려지거나 렉이 걸릴 수 있습니다.
해결방안은 다음과 같습니다.
B-프레임 없애기!
둥영상을 재인코딩하여 B-프레임을 전부 없애버리면 됩니다! 다음 ffmpeg
명령을 실행합니다:
ffmpeg -i 입력-둥영상.mp4 -bf 0 출력-둥영상.mp4
참고로 사용된 인코더의 종류에 따라, 다른 옵션값을 사용해야 될 수도 있습니다. 예를 들어:
ffmpeg -i 입력-둥영상.mp4 -c:v libx264 -x264-params bframes=0 출력-둥영상.mp4
탐색이 부드러운 둥영상들
만약 탐색이 부드러운 둥영상을 재생해보고 싶고, 닌텐도 스위치를 가지고 있다면, 이것을 시도해보실 수 있습니다. 닌텐도 스위치 상 저장한 게임 캡쳐 영상은 전부 I와 P-프레임으로만 구성되어 있습니다. 한번 다른 기기로 옮겨서 재생과 탐색을 시도해보세요! 만약 재인코딩하는 것이 귀찮으시다면 부드러운 탐색을 경험해보실 수 있는 좋은 예시입니다.