ExoPlayer 내부 살펴보기 — 컴포넌트 상호작용

goddoro
8 min readMay 15, 2022

--

안녕하세요 개발자 doro입니다.

ExoPlayer는 An Extensible Media Player 라는 타이틀을 가지고 있고 이런 제목에 맞게 Customize하기 좋습니다. 그렇다면 ExoPlayer가 내부적으로 어떤 컴포넌트들을 가지고 있고 어떤 동작을 하며 미디어를 재생할 수 있을까요?

Why Know?

라이브러리의 가장 큰 장점은 내부 구현 로직을 몰라도 인터페이스만 가지고 원하는 기능을 간단하게 구현해 낼 수 있다는 점입니다. ( 장점이자 단점이라고 생각합니다)

ExoPlayer도 마찬가지입니다. ExoPlayer에게 미디어 소스만 알려준다면 쉽게 미디어를 재생할 수 있습니다.

하지만 유저가 미디어를 재생하는 기기는 너무나도 다양하고 환경도 제 각각입니다. 또한 서비스 하고 있는 도메인에 따라서도 재생 경험은 달라질 수 밖에 없습니다.

Various Mobile Video Platform

예를 들면, TikTok이나 Reels같은 숏츠 플랫폼의 경우에는 1분 이하의 영상을 빠르게 스냅핑하며 컨텐츠를 소비할 수 있어야 합니다. Watcha같은 OTT 컨텐츠들은 10분 이상의 긴 영상을 안정적으로 스트리밍할 수 있어야 하죠.

기기별 사용경험은 또 어떨까요. Android TV의 미디어 재생은 대부분 안정적인 네트워크 안에서 이루어지는 반면에 모바일 환경은 대중교통을 사용한다거나 사람이 적은 곳에서 많은 곳으로 이동하는 등, 더욱 다양해지기 마련입니다.

이렇게 미디어를 재생하는 사용 경험은 다양할 수 밖에 없는데요. 라이브러리를 서비스의 성격에 맞게 Customize 한다면 좀 더 최적화된 환경에서 좋은 재생 경험을 가질 수 있을 것 같습니다.

ExoPlayer Component

이제 ExoPlayer가 내부적으로 어떻게 동작하고 있는지에 대해 알아보려고 하는데요. 그 전에 등장인물부터 파악해야 할 듯합니다.

ExoPlayer에는 어떤 컴포넌트들이 존재하며 각자 무슨 역할을 하고 있을까요?

ExoPlayer Components

MediaSource

DataSource ( Local or Remote Repository )로부터 미디어 파일을 가져오고, 버퍼링 하기 위한 버퍼 메모리를 할당하여 데이터를 저장하는 역할을 합니다.

Renderer

MediaSource로부터 받은 데이터를 Decode하며 Display( or Output audio) 해주는 역할, 크게 VideoRendererAudioRenderer로 나뉘고 경우에 따라 Subtitle Renderer 또는 Metadata Renderer도 존재합니다.

TrackSelector

MediaSourceDataSource로부터 전달받은 여러 가지 미디어 트랙 중 어느 트랙으로 재생해야할지 결정합니다. 미디어를 재생하는 기기의 Capabilities 도 고려하여 MediaSource에게 재생 가능한 트랙을 전달해줍니다.

LoadControl

MediaSource에 존재하는 버퍼의 상황에 따라 버퍼링을 제어하고 Player에게 언제 동영상이 재생되어야 하는지를 제어하는 역할을 합니다.

How Interaction

그렇다면 이 컴포넌트들은 서로 어떻게 역할을 분담해서 미디어를 재생할까요?

DataSource의 미디어 데이터를 MediaSource 가 가져오면서 플레이어의 협력은 시작됩니다. MediaSource는 미디어 파일을 바로 재생하는 것이 아니라 어떤 트랙으로 재생할지부터 결정해야 합니다.

이 때 두 가지의 정보가 필요한데요.

첫 번째는 DataSource 로부터 받은 트랙들을 가지고 만든 TrackGroups 입니다. Adaptive StreamingMaster 파일이 여러 가지 트랙을 가지고 있고, 이 중에 재생 가능한 트랙을 결정할 수 있습니다.

DataSource가 전달해준 사용가능한 Track들

두 번째는, 네트워크 상태나 재생하는 기기의 Capabilities 등 여러 가지 Metadata 를 담은 Render Capabilties 입니다.

아무리 고스펙의 트랙을 DataSource 로부터 전달받았다고 하더라도 현재 기기자체가 저사양이거나 네트워크 상태가 좋지 않다면 재생할 수 있는 트랙들도 달라지게 될 것입니다.

TrackGroupsRenderCapabilitiesTrackSelector에게 전달되고, TrackSelector 의 내부 알고리즘에 의하여 TrackSelections 를 생성하게 됩니다. 이는 앞으로 ExoPlayer에서 사용할 미디어의 트랙정보입니다.

TrackSelectorTrackSelectionsMediaSource에게 전달해준다면 비로소 MediaSourceDataSource에게 원하는 트랙에 해당하는 미디어 데이터를 요청할 수 있는 준비가 완료된 것입니다.

버퍼링 Start & Stop

MediaSource는 버퍼를 할당하고 그 안에, 데이터를 차곡차곡 쌓기 시작합니다. 이 때 미디어를 바로 재생하는 것이 아니라 버퍼에 특정량 이상이 쌓여야만 미디어를 재생할 수 있습니다. 이 과정에서 LoadControl 이 관여하게 됩니다.

아래는 LoadControl 의 버퍼와 재생에 관련한 제어 값들을 Customize한 코드입니다. 버퍼링은 얼만큼까지 할지, 버퍼의 양에 따라 언제 재생을 시작할지 등등 여러 가지 값을 설정할 수 있습니다.

Customized LoadControl

LoadControl 은 쉼없이 MediaSource 의 버퍼를 바라보며 버퍼링과 재생에 관여하게 되는데요.

버퍼링과 재생이 동시에 진행될 때, Renderer가 소비하는 데이터보다 버퍼링하는 속도가 더 빠르다면 버퍼 메모리는 가득 차게되고 더이상 데이터를 저장할 수 없는 상태가 됩니다. 그 때 LoadControl 은 버퍼링을 멈춥니다.

LoadControl 에 설정된 Min Buffer Duration 까지는 버퍼링을 하지 않고 Renderer가 데이터를 소비하기만 합니다. DataSource 로부터 데이터를 전달받지 않게 되는 것이죠.

버퍼의 양이 Min Buffer Duration 에 도달하게 되면LoadControl은 버퍼링을 Resume 하려고 할겁니다.

다시 데이터를 버퍼링하기 전에 TrackSelector 도 관여하게 되는데요. 어떤 트랙의 데이터를 버퍼로 채울지 재결정합니다. 기기의 상태에 별 다른 문제 없다면 아마 같은 트랙으로 미디어를 버퍼링하게 될 것입니다.

Buffering

이런식으로 ExoPlayer에서는 안정적으로 미디어를 재생하는 로직을 가지고 있습니다. 하지만, 유저의 네트워크 상태가 안좋을때는 어떤 일이 일어날까요?

만일 네트워크가 아예 끊킨 상태라면, DataSource 로부터 데이터를 아예 전달받지 못하게 되므로 흔히 말하는 버퍼링이라는 것을 경험하게 됩니다. 네트워크에 연결되기 전까지는 버퍼의 데이터를 사용할 수 없으므로 재생을 할 수도 없고 플레이어는 멈추게 되겠죠.

불안정한 네트워크라면 버퍼에 데이터가 Min Buffer Duration 에 도달했을 때 TrackSelector가 트랙을 재설정할 것입니다. 낮은 트랙으로 재설정하게 되면 버퍼링하는 데이터의 크기가 작아지게 되고, 버퍼링 속도가 빨라져 안좋은 스펙의 트랙이지만 안정적으로 미디어를 재생할 수 있게 되는것이죠.

마치며

ExoPlayer의 미디어 재생 로직을 안다고 해서 내가 운영하고 있는 서비스가 바로 좋아지는 것은 아닙니다. 본 포스팅의 지식은 단지 최적화할 포인트를 아는 것, 어느 부분의 코드를 뜯어볼지 감을 잡을 수 있는 것이 전부라고 생각이 드는데요.

결국엔 정성들여 삽질 하는 것이 필요합니다. 원리와 로직을 알고 삽질을 한다면 조금 더 현명하게 효율적으로 삽질을 할 수 있을 겁니다.

감사합니다.

Reference

https://americanopeople.tistory.com/336

https://www.youtube.com/watch?v=jAZn-J1I8Eg

--

--

goddoro
goddoro

Written by goddoro

TVING에서 동영상 플레이어를 개발하고 있습니다

No responses yet