오늘날 미디어 중심 앱에서는 원활하고 중단 없는 재생 환경을 제공하는 것이 즐거운 사용자 환경의 핵심입니다. 사용자는 동영상이 즉시 시작되고 일시중지 없이 원활하게 재생되기를 기대합니다.
핵심 과제는 지연 시간입니다. 기존에는 사용자가 재생할 항목을 선택한 후에만 동영상 플레이어가 연결, 다운로드, 파싱, 버퍼링과 같은 작업을 시작했습니다. 이러한 사후 대응 방식은 오늘날의 짧은 형식 동영상 컨텍스트에서는 느립니다. 해결책은 선제적으로 대응하는 것입니다. 사용자가 다음에 시청할 콘텐츠를 예측하고 미리 콘텐츠를 준비해야 합니다. 이것이 사전 로드의 본질입니다.
미리 로드의 주요 이점은 다음과 같습니다.
- 🚀 더 빠른 재생 시작: 동영상이 이미 준비되어 있어 항목 간 전환이 더 빠르고 즉시 시작됩니다.
- 📉 버퍼링 감소: 데이터를 사전 로드하여 네트워크 문제 등으로 인해 재생이 중단될 가능성이 훨씬 줄어듭니다.
- ✨ 더 원활한 사용자 환경: 시작 속도가 빨라지고 버퍼링이 줄어들어 사용자가 더 부드럽고 원활한 상호작용을 즐길 수 있습니다.
3부로 구성된 이 시리즈에서는 구성요소를 (사전) 로드하기 위한 Media3의 강력한 유틸리티를 소개하고 자세히 살펴봅니다.
- 1부에서는 Media3에서 사용할 수 있는 다양한 사전 로드 전략을 이해하고, PreloadConfiguration을 사용 설정하고 DefaultPreloadManager를 설정하여 앱이 항목을 사전 로드할 수 있도록 하는 등 기본 사항을 다룹니다. 이 블로그를 끝까지 읽으면 구성된 순위와 재생 시간으로 미디어 항목을 미리 로드하고 재생할 수 있습니다.
- 2부에서는 분석을 위한 리스너 사용, 슬라이딩 윈도우 패턴, DefaultPreloadManager 및 ExoPlayer의 맞춤 공유 구성요소와 같은 프로덕션 준비 상태의 권장사항 탐색 등 DefaultPreloadManager의 고급 주제를 자세히 살펴봅니다.
- 3부에서는 DefaultPreloadManager를 사용한 디스크 캐싱에 대해 자세히 알아보겠습니다.
미리 로드가 해결책입니다. 🦸♀️
사전 로드의 핵심 아이디어는 간단합니다. 미디어 콘텐츠를 필요하기 전에 로드하는 것입니다. 사용자가 다음 동영상으로 스와이프할 때쯤이면 동영상의 첫 번째 세그먼트가 이미 다운로드되어 즉시 재생할 수 있습니다.
레스토랑과 비슷하다고 생각하면 됩니다. 바쁜 주방에서는 주문이 들어올 때까지 양파를 썰지 않습니다. 🧅 미리 준비 작업을 합니다. 사전 로드는 동영상 플레이어를 위한 준비 작업입니다.
미리 로드를 사용 설정하면 사용자가 다음 항목으로 건너뛸 때 재생 버퍼가 다음 항목에 도달하기 전에 조인 지연 시간을 최소화하는 데 도움이 됩니다. 다음 창의 첫 번째 기간이 준비되고 동영상, 오디오, 텍스트 샘플이 버퍼링됩니다. 미리 로드된 기간은 이후 버퍼링된 샘플을 즉시 사용할 수 있는 플레이어 큐에 추가되며 렌더링을 위해 코덱에 피드하도록 준비됩니다.
Media3에는 프리로드에 관한 두 가지 기본 API가 있으며, 각 API는 서로 다른 사용 사례에 적합합니다. 적절한 API를 선택하는 것이 첫 번째 단계입니다.
1. PreloadConfiguration을 사용하여 재생목록 항목 미리 로드
이는 재생 순서를 예측할 수 있는 재생목록과 같은 선형 순차 미디어에 유용한 간단한 접근 방식입니다 (예: 일련의 에피소드). ExoPlayer의 재생목록 API를 사용하여 플레이어에게 전체 미디어 항목 목록을 제공하고 플레이어의 PreloadConfiguration을 설정하면 구성된 대로 시퀀스의 다음 항목이 자동으로 미리 로드됩니다. 이 API는 사용자가 재생 버퍼가 이미 다음 항목으로 겹치기 전에 다음 항목으로 건너뛸 때 조인 지연 시간을 최적화하려고 시도합니다.
미리 로드는 현재 재생에 필요한 미디어가 로드되지 않을 경우에만 시작되므로 기본 재생과 동일한 대역폭을 사용하지 않습니다.
여전히 미리 로드가 필요한지 확실하지 않다면 이 API는 미리 로드를 시도해 볼 수 있는 좋은 옵션입니다.
player.preloadConfiguration = PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)
위와 같은 PreloadConfiguration을 사용하면 플레이어가 재생목록에서 다음 항목 미디어의 5초 분량을 미리 로드하려고 시도합니다.
재생목록 미리 로드를 사용 설정한 후에는 PreloadConfiguration.DEFAULT를 사용하여 재생목록 미리 로드를 다시 사용 중지할 수 있습니다.
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. PreloadManager를 사용하여 동적 목록 미리 로드
사용자 상호작용에 따라 '다음' 항목이 결정되는 세로 피드나 캐러셀과 같은 동적 UI에는 PreloadManager API가 적합합니다. 이는 적극적으로 미리 로드하도록 특별히 설계된 Media3 ExoPlayer 라이브러리 내의 강력한 새로운 독립형 구성요소입니다. 잠재적인 MediaSource 컬렉션을 관리하고 사용자의 현재 위치와의 근접성을 기반으로 우선순위를 지정하며, 짧은 형식 동영상의 동적 피드와 같은 복잡한 시나리오에 적합한 사전 로드할 항목에 대한 세부적인 제어를 제공합니다.
PreloadManager 설정
DefaultPreloadManager는 PreloadManager의 표준 구현입니다.
DefaultPreloadManager 빌더는 DefaultPreloadManager와 미리 로드된 콘텐츠를 재생할 ExoPlayer 인스턴스를 모두 빌드할 수 있습니다. DefaultPreloadManager를 만들려면 타겟 프리로드 상태 컨트롤을 전달해야 합니다. 프리로드 관리자는 이를 쿼리하여 항목에 로드할 양을 확인할 수 있습니다. 아래 섹션에서 TargetPreloadStatusControl의 예를 설명하고 정의합니다.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
ExoPlayer와 DefaultPreloadManager에 동일한 빌더를 사용해야 합니다. 이렇게 하면 두 구성요소의 내부 구성요소가 올바르게 공유됩니다.
이상입니다 이제 관리자가 명령을 받을 준비가 되었습니다.
TargetPreloadStatusControl을 사용하여 기간 및 순위 구성
예를 들어 동영상 10초를 미리 로드하려면 어떻게 해야 할까요? 캐러셀에서 미디어 항목의 위치를 제공하면 DefaultPreloadManager는 사용자가 현재 재생 중인 항목과의 거리에 따라 항목 로딩의 우선순위를 지정합니다.
미리 로드할 항목의 재생 시간을 제어하려면 DefaultPreloadManager.PreloadStatus를 반환하여 이를 알리면 됩니다.
예를 들면 다음과 같습니다.
- 항목 'A'가 우선순위가 가장 높으므로 5초 길이의 동영상을 로드합니다.
- 항목 'B'는 중간 우선순위이지만 항목에 도달하면 3초 길이의 동영상을 로드합니다.
- 항목 'C'는 우선순위가 낮으므로 트랙만 로드합니다.
- 항목 'D'는 우선순위가 더 낮으므로 준비만 하면 됩니다.
- 다른 항목은 멀리 떨어져 있습니다. 아무것도 미리 로드하지 마세요.
이 세분화된 제어를 통해 리소스 사용률을 최적화할 수 있으며, 이는 원활한 재생을 위해 권장됩니다.
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus class MyTargetPreloadStatusControl( currentPlayingIndex: Int = C.INDEX_UNSET ) : TargetPreloadStatusControl<Int,PreloadStatus> { // The app is responsible for updating this based on UI state override fun getTargetPreloadStatus(index: Int): PreloadStatus? { val distance = index - currentPlayingIndex // Adjacent items (Next): preload 5 seconds if (distance == 1) { // Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position return PreloadStatus.specifiedRangeLoaded(5000L) } // Adjacent items (Previous): preload 3 seconds else if (distance == -1) { // Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position return PreloadStatus.specifiedRangeLoaded(3000L) } // Items two positions away: just select tracks else if (distance) == 2) { // Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED return PreloadStatus.TRACKS_SELECTED } // Items four positions away: just select prepare else if (abs(distance) <= 4) { // Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED return PreloadStatus.SOURCE_PREPARED } // All other items are too far away return null } }
도움말: PreloadManager는 이전 항목과 다음 항목을 모두 미리 로드할 수 있지만 PreloadConfiguration은 다음 항목만 미리 로드합니다.
미리 로드 항목 관리
관리자가 생성되었으므로 이제 관리자에게 작업할 내용을 알려줄 수 있습니다. 사용자가 피드를 스크롤하면 예정된 동영상을 식별하여 관리자에 추가합니다. PreloadManager와의 상호작용은 UI와 미리 로드 엔진 간의 상태 기반 대화입니다.
1. 미디어 항목 추가
피드를 채울 때 추적해야 하는 미디어의 관리자에게 알려야 합니다. 시작하는 경우 미리 로드하려는 전체 목록을 추가할 수 있습니다. 그런 다음 필요할 때마다 목록에 항목을 하나씩 추가할 수 있습니다. 사전 로드 목록에 있는 항목을 완전히 제어할 수 있으므로 관리자에서 추가 및 삭제되는 항목도 관리해야 합니다.
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}이제 관리자가 백그라운드에서 이 MediaItem의 데이터를 가져오기 시작합니다.
추가한 후 관리자에게 새 목록을 다시 평가하도록 요청합니다 (항목을 추가/ 삭제했거나 사용자가 새 항목을 재생하도록 전환하는 등 변경사항이 있음을 암시).
preloadManager.invalidate()
2. 항목 가져오기 및 재생
이제 기본 재생 로직이 나옵니다. 사용자가 해당 동영상을 재생하기로 결정한 경우 새 MediaSource를 만들 필요가 없습니다. 대신 PreloadManager에게 이미 준비된 것을 요청합니다. MediaItem을 사용하여 Preload Manager에서 MediaSource를 가져올 수 있습니다.
PreloadManager에서 가져온 항목이 null이면 mediaItem이 아직 미리 로드되지 않았거나 PreloadMamager에 추가되지 않았으므로 mediaItem을 직접 설정합니다.
// When a media item is about to display on the screen val mediaSource = preloadManager.getMediaSource(mediaItem) if (mediaSource!= null) { player.setMediaSource(mediaSource) } else { // If mediaSource is null, that mediaItem hasn't been added yet. // So, send it directly to the player. player.setMediaItem(mediaItem) } player.prepare() // When the media item is displaying at the center of the screen player.play()
PreloadManager에서 가져온 MediaSource를 준비하면 이미 메모리에 있는 데이터를 사용하여 미리 로드에서 재생으로 원활하게 전환할 수 있습니다. 이로 인해 시작 시간이 빨라집니다.
3. 현재 색인을 UI와 동기화
피드 / 목록이 동적일 수 있으므로 항상 현재 색인에 가장 가까운 항목을 미리 로드하도록 PreloadManager에 현재 재생 색인을 알려야 합니다.
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. 항목 삭제하기
관리자의 효율성을 유지하려면 사용자의 현재 위치에서 멀리 떨어진 항목과 같이 더 이상 추적할 필요가 없는 항목을 삭제해야 합니다.
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
한 번에 모든 항목을 삭제해야 하는 경우 preloadManager.reset()를 호출하면 됩니다.
5. 관리자 해제
더 이상 PreloadManager가 필요하지 않으면 (예: UI가 소멸된 경우) 리소스를 확보하기 위해 해제해야 합니다. 이를 수행하기에 적합한 위치는 이미 플레이어의 리소스를 해제하는 곳입니다. 더 이상 사전 로드가 필요하지 않은 경우 플레이어 전에 관리자를 해제하는 것이 좋습니다. 플레이어는 계속 플레이할 수 있기 때문입니다.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
데모 시현
실제 사례를 확인해 보세요 👍
아래 데모에서 오른쪽에는 PreloadManager의 영향이 표시되어 로드 시간이 더 빠른 반면 왼쪽에는 기존 환경이 표시됩니다. 데모의 코드 샘플을 볼 수도 있습니다. (보너스: 모든 동영상의 시작 지연 시간도 표시됩니다.)
다음 단계
1부 끝! 이제 동적 미리 로드 시스템을 빌드할 수 있는 도구가 있습니다. PreloadConfiguration를 사용하여 ExoPlayer에서 재생목록의 다음 항목을 미리 로드하거나 DefaultPreloadManager를 설정하고, 항목을 즉시 추가 및 삭제하고, 타겟 미리 로드 상태를 구성하고, 재생을 위해 미리 로드된 콘텐츠를 올바르게 가져올 수 있습니다.
2부에서는 DefaultPreloadManager에 대해 자세히 알아보겠습니다. 사전 로드 이벤트를 수신하는 방법을 살펴보고, 슬라이딩 윈도우를 사용하여 메모리 문제를 방지하는 등의 권장사항을 논의하고, ExoPlayer 및 DefaultPreloadManager의 맞춤 공유 구성요소를 자세히 살펴보겠습니다.
공유하고 싶은 의견이 있으신가요? 여러분의 의견을 기다리고 있습니다.
계속해서 소식을 확인하고 앱 속도를 개선하세요. 🚀
계속 읽기
-
제품 소식
Media3을 사용한 미디어 미리 로드에 관한 3부작 시리즈의 두 번째 편에 오신 것을 환영합니다. 이 시리즈는 Android 앱에서 응답성이 높고 지연 시간이 짧은 미디어 환경을 빌드하는 과정을 안내하도록 설계되었습니다.
Mayuri Khinvasara Khabya • 읽는 데 9분 소요
-
제품 소식
이제 Android Emulator를 사용하면 멀티 디바이스 상호작용을 그 어느 때보다 쉽게 테스트할 수 있습니다.
Steven Jenkins • 전문 길이: 2분
-
제품 소식
모든 개발자의 AI 워크플로와 요구사항은 고유하며, AI가 개발에 어떤 도움을 줄지 선택할 수 있는 것이 중요합니다. 1월에는 Android 스튜디오에서 AI 기능을 구동하는 데 로컬 또는 원격 AI 모델을 선택할 수 있는 기능이 도입되었습니다.
Matthew Warner • 전문 길이: 2분
소식 받아 보기
Android 개발 관련 최신 정보를 이메일로 받아 보세요.