ExoPlayer: co to jest, możliwości i konfiguracja

Autor: IT Sectr Opublikowano: 2026-05-23 Czas czytania: 8 min

ExoPlayer to otwarta biblioteka odtwarzacza multimedialnego dla Android, opracowana przez Google jako alternatywa dla wbudowanego MediaPlayer. ExoPlayer zapewnia odtwarzanie audio i wideo w różnych formatach, w tym DASH, HLS, SmoothStreaming i zwykłych plikach multimedialnych, poprzez jednolity API z obsługą streamingu adaptacyjnego. Według Google I/O (2024), ExoPlayer jest używany w ponad 60 000 aplikacji Android, w tym YouTube, Google TV i Netflix.

Najważniejsze

  • ExoPlayer to biblioteka odtwarzacza multimedialnego z otwartym kodem źródłowym dla Android od Google.
  • Formaty wieloplatformowe — ExoPlayer obsługuje DASH, HLS, SmoothStreaming i RTSP poprzez modułowy system rozszerzeń.
  • Dostosowanie — każdy komponent odtwarzacza (renderer, źródło danych, DRM) może zostać zastąpiony własną implementacją.
  • Canvas i Compose — ExoPlayer integruje się zarówno z tradycyjnym podejściem View (SurfaceView), jak i z Jetpack Compose.
  • DRM — obsługa Widevine, PlayReady i ClearKey poprzez modułowy system DRM.

Co to jest ExoPlayer?

ExoPlayer to biblioteka do odtwarzania multimediów na Android z otwartym kodem źródłowym (Apache 2.0), której pierwsza wersja została wydana przez Google w 2014 roku. W przeciwieństwie do wbudowanego MediaPlayer, który jest cienką otoczką wokół systemowego kodeka multimedialnego (MediaCodec), ExoPlayer jest zaimplementowany w całości na poziomie Java/Kotlin, co daje programistom pełną kontrolę nad każdym etapem odtwarzania.

Architektonicznie ExoPlayer jest zbudowany na zasadzie modułowej: każdy aspekt odtwarzania jest realizowany przez osobny komponent. Główny moduł (exoplayer-core) zawiera odtwarzacz, rendery, selektory ścieżek i zarządzanie buforem. Dodatkowe moduły (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) dodają obsługę odpowiednich protokołów streamingu. Taka architektura pozwala aplikacjom podłączać tylko niezbędne komponenty, minimalizując rozmiar APK.

ExoPlayer 2 (obecna główna wersja) została wydana w 2018 roku i przyniosła gruntowną przebudowę API: wprowadzenie Player Interface, obsługę Compose poprzez AndroidX Media3, ulepszone przetwarzanie błędów i adaptacyjne algorytmy wyboru ścieżek. Począwszy od wersji 2.19 (2024), ExoPlayer stał się częścią biblioteki AndroidX Media, co uprościło integrację i aktualizację poprzez standardowy menedżer zależności Android.

Architektura ExoPlayer

U podstaw ExoPlayer leży komponent ExoPlayerImpl, który zarządza cyklem życia odtwarzania. Zawiera on MediaSource (źródło multimediów), TrackSelector (wybór ścieżek), LoadControl (zarządzanie buforowaniem) i listę Renderer (rendery dla wideo, audio, napisów i metadanych). Każdy komponent może zostać zastąpiony własną implementacją poprzez Builder lub metody fabryczne.

Do renderowania wideo ExoPlayer używa SurfaceView, TextureView lub SphericalSurfaceView (dla wideo 360 stopni). Zalecanym wariantem jest SurfaceView, ponieważ zapewnia przyspieszenie sprzętowe i minimalne zużycie energii. Dla Jetpack Compose biblioteka AndroidX Media3 udostępnia komponent `AndroidView`, opakowujący SurfaceView, oraz eksperymentalny `Media3Compose` z natywną integracją Compose.

Możliwości ExoPlayer

ExoPlayer oferuje szeroki zestaw funkcji wykraczających poza zwykły odtwarzacz multimedialny. Główne możliwości obejmują obsługę wszystkich popularnych protokołów streamingu, elastyczny system DRM, adaptacyjne przełączanie bitrate'u (ABR) i narzędzia analityki odtwarzania.

FunkcjaOpisModuł
DASHAdaptacyjny streaming zgodny ze standardem MPEGexoplayer-dash
HLSHTTP Live Streaming od Appleexoplayer-hls
SmoothStreamingAdaptacyjny streaming od Microsoftexoplayer-smoothstreaming
RTSPReal-Time Streaming Protocol dla transmisji na żywoexoplayer-rtsp
WidevineOchrona treści DRMexoplayer-drm
ConcatenationŁączenie wielu plików multimedialnychexoplayer-core
AdsIntegracja IMA SDK dla reklamexoplayer-ima

Adaptacyjne przełączanie bitrate'u

ABR (Adaptive Bitrate) w ExoPlayer jest zaimplementowany poprzez interfejs AdaptiveTrackSelection. Domyślnie używany jest AdaptiveTrackSelectionFactory, który tworzy DefaultAdaptiveTrackSelection — zrównoważony algorytm uwzględniający przepustowość sieci i rozmiar bufora. Dla specyficznych scenariuszy można podłączyć alternatywne implementacje: BOLA (minimalizacja przełączeń), RandomAdaptiveTrackSelection (testowanie) lub własną implementację poprzez interfejs TrackSelection.

BandwidthMeter to kolejny kluczowy komponent odpowiedzialny za pomiar przepustowości sieci. Domyślnie używany jest DefaultBandwidthMeter, który zbiera statystyki ze wszystkich żądań HTTP odtwarzacza. Programista może go rozszerzyć, aby uwzględnić dodatkowe czynniki: typ sieci (Wi-Fi, 4G, 5G), sygnał stacji bazowej lub koszt transmisji dla użytkownika.

DRM i ochrona treści

ExoPlayer obsługuje Widevine (L1, L3), PlayReady i ClearKey DRM. Uzyskiwanie licencji konfiguruje się poprzez DrmSessionManager, który współpracuje z serwerem licencji. Dla wideo premium (4K HDR) wymagane jest sprzętowe wsparcie Widevine L1, które zapewnia ochronę na poziomie chipa i zapobiega przechwytywaniu ekranu. Wybór systemu DRM zależy od docelowej platformy: Widevine jest używany na Android i Chromecast, PlayReady na Xbox i Windows, FairPlay na iOS i Apple TV. ExoPlayer automatycznie określa dostępny system DRM na podstawie pliku MPD i nie wymaga ręcznej konfiguracji dla podstawowych scenariuszy.

Jak zintegrować ExoPlayer z projektem Android

Podłączenie ExoPlayer do projektu Android wykonuje się przez zależności Gradle. Począwszy od wersji 2.19, ExoPlayer wchodzi w skład AndroidX Media (androidx.media3), co zapewnia zgodność z Jetpack Compose i innymi komponentami AndroidX. Omówimy integrację krok po kroku w Kotlin.

Dodawanie zależności

Dodaj moduły ExoPlayer do pliku build.gradle (Module). Minimalny zestaw obejmuje core, ui i moduł dla wymaganego protokołu streamingu. Do odtwarzania treści DASH potrzebny jest exoplayer-dash, do HLS — exoplayer-hls.

groovy
dependencies {
    implementation "androidx.media3:media3-exoplayer:1.5.0"
    implementation "androidx.media3:media3-ui:1.5.0"
    implementation "androidx.media3:media3-exoplayer-dash:1.5.0"
    implementation "androidx.media3:media3-exoplayer-hls:1.5.0"
}

Podstawowa integracja w Activity

Tworzenie i konfiguracja odtwarzacza w Activity lub Fragment. ExoPlayer używa PlayerView (lub StyledPlayerView do dostosowania) do wyświetlania wideo i wbudowanych elementów sterowania. Minimalna konfiguracja obejmuje utworzenie odtwarzacza przez ExoPlayer.Builder i przekazanie MediaItem z URI źródła.

kotlin
class PlayerActivity : AppCompatActivity() {

    private var player: ExoPlayer? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_player)

        player = ExoPlayer.Builder(this).build()
        val playerView = findViewById<StyledPlayerView>(R.id.playerView)
        playerView.player = player

        val mediaItem = MediaItem
            .Builder()
            .setUri("https://example.com/video.mp4")
            .build()
        player?.setMediaItem(mediaItem)
        player?.prepare()
    }

    override fun onDestroy() {
        player?.release()
        super.onDestroy()
    }
}

Obsługa błędów i stanów

Dla aplikacji produkcyjnych niezbędna jest obsługa możliwych błędów odtwarzania: awarie sieci, nieobsługiwane formaty, błędy licencjonowania DRM. ExoPlayer udostępnia interfejs Player.Listener z metodami onPlayerError, onPlaybackStateChanged i onPlayWhenReadyChanged. Zaleca się wyświetlanie użytkownikowi informacyjnych komunikatów o błędach z możliwością ponowienia.

ExoPlayer kontra MediaPlayer: porównanie

Wybór między ExoPlayer a wbudowanym MediaPlayer to częste pytanie przy tworzeniu aplikacji Android. MediaPlayer jest częścią Android SDK od wersji 1.0, podczas gdy ExoPlayer to biblioteka wymagająca podłączenia przez Gradle. Omówimy ich różnice według kluczowych kryteriów.

KryteriumExoPlayerMediaPlayer
ArchitekturaModułowa, w całości w Java/KotlinOtoczka wokół systemowych komponentów C++
StreamingDASH, HLS, SmoothStreaming, RTSPTylko pliki lokalne i HLS (Android 9+)
DostosowaniePełne (każdy komponent można zastąpić)Minimalne (tylko parametry)
AktualizacjePrzez Google Play lub APK (niezależnie od systemu)Tylko przez aktualizację Android (OTA)
Rozmiar APK+1-3 MB (w zależności od modułów)0 (część systemu)
Min SDKAPI 16+ (Android 4.1)API 1+
DRMWidevine, PlayReady, ClearKeyWidevine (ograniczenie)

ExoPlayer wygrywa w scenariuszach wymagających streamingu (DASH, HLS), dostosowania UI, obsługi DRM i niezależności od wersji Android. MediaPlayer nadaje się do prostych aplikacji odtwarzających lokalne pliki multimedialne, gdzie rozmiar APK jest krytyczny i nie ma wymagań dotyczących streamingu adaptacyjnego. Dla nowoczesnych aplikacji z treściami z sieci ExoPlayer jest jednoznacznym wyborem.

Wyjątek — aplikacje z minimalnym SDK poniżej API 16 (Android 4.1), których praktycznie nie ma już na rynku. Dla wszystkich aplikacji z targetSdk 33+ i minimalnym SDK 21+ ExoPlayer jest nie tylko preferowany, ale wręcz niezbędny do obsługi nowoczesnych formatów, takich jak AV1 i Dolby Vision poprzez odpowiednie rozszerzenia.

Zaawansowana konfiguracja ExoPlayer

Dla aplikacji produkcyjnych podstawowa integracja ExoPlayer często wymaga dodatkowej konfiguracji: zarządzanie buforowaniem, optymalizacja buforowania dla sieci mobilnych, integracja z analityką i dostosowanie wyboru ścieżek audio. Omówimy zaawansowane scenariusze użycia.

Buforowanie treści

CacheDataSourceFactory pozwala buforować pobrane segmenty w lokalnym magazynie, co oszczędza transfer przy ponownym oglądaniu i zapewnia odtwarzanie offline. ExoPlayer używa SimpleCache z biblioteki exoplayer-cas — buforowanie plikowe z obsługą LRU-ewakuacji i limitów rozmiaru.

kotlin
val cache = SimpleCache(
    cacheDir,
    LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024),
    AppDatabaseProvider(this)
)

val cacheDataSourceFactory = CacheDataSource
    .Factory()
    .setCache(cache)

val player = ExoPlayer.Builder(this)
    .setMediaSourceFactory(
        DefaultMediaSourceFactory(cacheDataSourceFactory)
    )
    .build()

Obsługa przełączania sieci

W aplikacjach mobilnych kluczowa jest obsługa przełączania między Wi-Fi a siecią komórkową. ExoPlayer udostępnia ConnectivityManager do śledzenia stanu sieci. W przypadku utraty połączenia zaleca się nie zatrzymywać odtwarzacza, ale przejść do stanu PAUSED z zachowaniem pozycji. Po przywróceniu połączenia — wznowić odtwarzanie z przeładowaniem segmentów.

Integracja z Jetpack Compose

Wraz z wydaniem AndroidX Media3 biblioteka otrzymała eksperymentalne wsparcie dla Jetpack Compose. Komponent `AndroidView` opakowuje SurfaceView lub PlayerView, zapewniając zgodność z hierarchią Compose. Do głębszej integracji używana jest biblioteka `androidx.media3:media3-ui-compose`, udostępniająca kompatybilne z Compose elementy sterowania odtwarzaczem.

kotlin
@Composable
fun VideoPlayer(uri: String) {
    val context = LocalContext.current
    val player = remember {
        ExoPlayer.Builder(context).build()
            .also { it.setMediaItem(MediaItem.fromUri(uri)) }
    }

    DisposableEffect(key = null) {
        player.prepare()
        onDispose { player.release() }
    }

    AndroidView(
        factory = { StyledPlayerView(context).also { it.player = player } }
    )
}

Często zadawane pytania

Jaka jest minimalna wersja Android dla ExoPlayer?

ExoPlayer obsługuje Android API 16+ (Android 4.1 Jelly Bean). Jednak dla DASH i HLS z segmentami fMP4 zaleca się API 21+ (Android 5.0 Lollipop). Moduły DRM (Widevine) wymagają API 19+, a sprzętowe dekodowanie HEVC jest dostępne od API 21.

Czy można używać ExoPlayer do audio bez wideo?

Tak, ExoPlayer doskonale nadaje się do audio. Do odtwarzania samego dźwięku nie jest wymagany SurfaceView ani PlayerView. ExoPlayer automatycznie wybierze renderer audio i będzie działać w tle. Do odtwarzania w tle zaleca się używanie MediaSessionService do integracji z systemowymi elementami sterowania.

Jak przełączać się między ścieżkami audio w ExoPlayer?

TrackSelector w ExoPlayer zarządza wyborem ścieżek audio. Do przełączania użyj player.getCurrentTracks().groups i player.setTrackSelectionParameters() z podaniem preferowanego języka audio. Dla strumieni DASH i HLS z wieloma ścieżkami audio przełączanie odbywa się bez przerywania odtwarzania.

Czy ExoPlayer obsługuje napisy?

Tak, ExoPlayer obsługuje wbudowane (w kontenerze MP4, WebM) i zewnętrzne napisy w formatach TTML, SRT, VTT i CEA-608. Do zewnętrznych napisów używany jest SingleSampleMediaSource lub MergingMediaSource do połączenia ze strumieniem wideo. Wyświetlanie stylizowanych napisów konfiguruje się przez CaptionStyleCompat.

Jak zmniejszyć opóźnienie przy streamingu na żywo w ExoPlayer?

Do Low-Latency streamingu skonfiguruj LoadControl z mniejszymi docelowymi wartościami bufora: użyj DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) dla HLS LL i DASH LL. Dodatkowo ustaw minPlaybackSpeed = 1.02 dla przyspieszonego wypełniania bufora przy opóźnieniu względem transmisji na żywo.

Podsumowanie

  • ExoPlayer — otwarta biblioteka odtwarzacza multimedialnego od Google z modułową architekturą i pełnym dostosowaniem.
  • Streaming adaptacyjny — obsługuje DASH, HLS, SmoothStreaming i RTSP poprzez modułowy system rozszerzeń.
  • DRM — Widevine, PlayReady i ClearKey integrują się przez moduł exoplayer-drm z jednolitym API.
  • Buforowanie — SimpleCache zapewnia odtwarzanie offline i oszczędność transferu przy ponownym oglądaniu.
  • Compose — od AndroidX Media3 ExoPlayer integruje się z Jetpack Compose przez AndroidView.
  • Dostosowanie — każdy komponent (MediaSource, TrackSelector, LoadControl, Renderer) może zostać zastąpiony.
  • Zalecany — używaj ExoPlayer dla wszystkich projektów wymagających streamingu, DRM lub dostosowania odtwarzania.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również