Strategia buforowania w ExoPlayerze
Badana wersja ExoPlayera: 2.9.6
Klasy implementujące interfejs LoadControl definiują strategię buforowania w ExoPlayerze. Strategia buforowania odpowiada na pytania takie jak:
- czy potrzebujemy załadować więcej danych medialnych?
- czy mamy wystarczająco dużo danych medialnych by rozpocząć odtwarzanie?
Strategia buforowania nie jest odpowiedzialna za zarządzanie buforami lub pobieranie danych medialnych (to jest MediaSource), lub odtwarzanie danych medialnych (to jest Renderer). Strategia buforowania jest agnostyczna w stosunku do odtwarzanego formatu mediów i ma jedynie rolę „konsultacyjną”. Może się czasami zdarzyć, że ExoPlayer „zapyta” LoadControl czy nowe dane medialne powinny być załadowane i zignoruje odpowiedź (np. ExoPlayer jest już w trakcie pobierania danych medialnych).
ExoPlayer przychodzi z domyślną implementacją, DefaultLoadControl. Jest to konfigurowalna implementacja interfejsu LoadControl.
DefaultLoadControl może być użyta do skonfigurowania np. :
- Ile milisekund (ms) danych medialnych ExoPlayer powinien buforować przed rozpoczęciem odtwarzania (określane jako bufferForPlaybackMs). ExoPlayer rozpocznie odtwarzanie jak tylko będzie miał co najmniej buforForPlaybackMs danych medialnych, nawet jeśli ExoPlayer nie zbuforował w pełni całego segmentu.
- Minimalna ilość zbuforowanych danych medialnych (w ms) zanim ExoPlayer zacznie ładować więcej danych (określana jako minBufferMs).
- Maksymalna ilość danych medialnych (w ms), które ExoPlayer powinien buforować zanim zatrzyma się by załadować więcej danych (określane jako maxBufferMs).
- Ile milisekund danych medialnych ExoPlayer powinien buforować przed wznowieniem odtwarzania po zdarzeniu rebuffering (określane jako bufferForPlaybackAfterRebufferMs).
DefaultLoadControl ma domyślne wartości dla każdego z tych ustawień. W v2.9.6, te wartości to:
bufferForPlaybackMs |
|
minBufferMs |
|
maxBufferMs |
|
bufferForPlaybackAfterRebufferMs |
Jednakże, wartości te różnią się w zależności od wersji ExoPlayera. Np. pomiędzy ExoPlayerem v2.7.3 a v2.8.0, maxBufferMs dla strumieni video zmienił się z 30 sekund na 50 sekund.
Modułowa architektura ExoPlayera pozwala również na zaimplementowanie własnej strategii buforowania (implementującej interfejs LoadControl) i podpięcie jej do ExoPlayera. Ale to temat na inny wpis.
Zmniejszanie czasu startu
W ExoPlayerze, łatwo jest skonfigurować jak dużo danych medialnych jest potrzebnych zanim rozpocznie się odtwarzanie. W pierwszej części tej serii blogów podkreślaliśmy znaczenie czasu uruchamiania jako metryki QoE. Raport Akamai opublikowany w 2016 r. wykazał, że „widzowie zaczną porzucać wideo, jeśli rozpoczęcie odtwarzania trwa dłużej niż dwie sekundy, a na każdą dodatkową sekundę opóźnienia, mniej więcej dodatkowe 6% widzów opuszcza film. przy 10-sekundowym opóźnieniu, prawie połowa widzów odeszła”.
ExoPlayer w wersji 2.9.6 wymaga domyślnie 2,5 sekundy danych multimedialnych buforowanych przed zainicjowaniem odtwarzania. Możliwe jest obniżenie czasu startu poprzez wymaganie mniejszej ilości danych do zbuforowania. Z jednej strony, obniżenie wartości buforowania danych multimedialnych spowoduje obniżenie czasu uruchamiania wideo, jednak minusem tego rozwiązania jest to, że może to również spowodować wzrost metryki buforowania podczas uruchamiania.
W pierwszej części tej serii blogów, użyliśmy wykresu radarowego do wizualizacji wpływu różnych kompromisów na 5 metryk QoE. Poniższy wykres pokazuje wpływ obniżenia minimalnej wymaganej ilości danych multimedialnych przed zainicjowaniem odtwarzania.
Ponieważ domyślna wartość bufferForPlaybackMs wynosząca 2,5 sekundy jest wartością konserwatywną, uważamy, że dobrym wyborem jest jej obniżenie.
Poniższy wykres pokazuje wpływ na czas uruchamiania dla strumienia 3 Mb/s przy zmianie wartości tej opcji konfiguracyjnej (nie biorąc pod uwagę czasu przelotu do serwera, ani tego, czy serwer musi pobierać zawartość z innego miejsca). Przykładowo, na łączu 4 Mbps odtwarzającym strumień 3 Mbps, skonfigurowanie ExoPlayera do rozpoczęcia odtwarzania po zbuforowaniu 1.5s danych multimedialnych oznacza, że teoretyczny czas startu wyniesie 1.1s, zamiast 1.9s przy domyślnej konfiguracji buforowania 2.5s danych multimedialnych.
Kolejna sekcja mówi o tym, jak skonfigurować ExoPlayera, aby obniżyć czas startu i opóźnienie machania ręką. Jeśli nie jesteś zaznajomiony z ExoPlayerem, zalecamy najpierw prześledzić Codelabs Google’a na temat strumieniowania mediów z ExoPlayerem.
Konfigurowanie DefaultLoadControl
Zakładając, że tworzysz swoją instancję ExoPlayera z domyślną implementacją LoadControl używając następującego kodu (lub podobnego):
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(),
new DefaultLoadControl())
Możesz skonfigurować DefaultLoadControl używając DefaultLoadControl.Builder:
/* Instantiate a DefaultLoadControl.Builder. */
DefaultLoadControl.Builder builder = new DefaultLoadControl.Builder();
/* Milisekundy danych multimedialnych buforowanych przed rozpoczęciem lub wznowieniem odtwarzania. */
final long loadControlStartBufferMs = 1500;
Skonfiguruj nowy DefaultLoadControl tak, aby korzystał z naszego ustawienia, ile milisekund danych medialnych musi być buforowanych przed rozpoczęciem lub wznowieniem odtwarzania po zdarzeniu akcji użytkownika.
builder.setBufferDurationMs(
DefaultLoadControl.DEFAULT MAX BUFFER MS,
loadControlStartBufferMs,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
/* Zbuduj rzeczywistą instancję DefaultLoadControl */
DefaultLoadControl loadControl = builder.createDefaultLoadControl();
/* Zainstaluj ExoPlayera z naszą skonfigurowaną DefaultLoadControl */
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(), loadControl);
Lowering Rebuffering Metrics for VOD Content
Poza konfiguracją ustawień, które prowadzą do skrócenia czasu uruchamiania, możesz skonfigurować DefaultLoadControl, aby ustalić ile danych medialnych buforować, co może wpłynąć na metryki rebufferingu dla treści VOD.
ExoPlayer v2.9.6 domyślnie załaduje 50 sekund danych medialnych do swojego wewnętrznego bufora jeśli będzie mógł (ustawienie maxBufferMs). W przypadku treści VOD, zwiększenie tej wartości da odtwarzaczowi więcej miejsca na radzenie sobie z wahaniami pasma sieciowego i niższe metryki rebufferów; minusem jest to, że zwiększy to również użycie pamięci przez ExoPlayera. Utrzymywanie niskiego zużycia pamięci jest ważne na urządzeniach low-end. Innym minusem jest marnowanie pasma w przypadku, gdy odtwarzanie zatrzyma się przedwcześnie.
Aby znaleźć wartość, która działa najlepiej dla twojej konfiguracji zawartości VOD, zalecamy przeprowadzenie testów A/B z różnymi wartościami opcji konfiguracyjnej, aby znaleźć taką, która daje dobry kompromis pomiędzy współczynnikiem odradzania a zużyciem pamięci. Zalecamy bycie konserwatywnym poprzez zwiększenie wartości do, np, 60 sekund na początku, aby sprawdzić, czy zapewnia to istotną różnicę dla metryk odświeżania.
Konfigurowanie DefaultLoadControl
Zakładamy, że tworzysz swoją instancję ExoPlayera z domyślną implementacją LoadControl (jak pokazano w poprzedniej sekcji Obniżanie czasu startu – Konfigurowanie DefaultLoadControl).
Możesz skonfigurować DefaultLoadControl używając DefaultLoadControl.Builder:
/* Instantiate a DefaultLoadControl.Builder. */
DefaultLoadControl.Builder builder = new
DefaultLoadControl.Builder();
/* Maksymalna ilość danych multimedialnych do zbuforowania (w milisekundach). */
final long loadControlMaxBufferMs = 60000;
/*Skonfiguruj DefaultLoadControl, aby korzystał z naszego ustawienia ile
milisekund danych medialnych ma być buforowanych. */
builder.setBufferDurationsMs(
DefaultLoadcontrol.DEFAULT MIN BUFFER MS,
loadControlMaxBufferMs,
/*Aby skrócić czas uruchamiania, zmień również linię poniżej */
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
/* Zbuduj rzeczywistą instancję DefaultLoadControl */
DefaultLoadControl loadControl = builder.createDefaultLoadControl();
/* Zainstaluj ExoPlayera z naszą skonfigurowaną DefaultLoadControl */
ExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(),
loadControl);
W przypadku, gdy minBufferMs i maxBufferMs będą miały różne wartości, ExoPlayer będzie miał burstowe zachowanie przy uzupełnianiu bufora. ExoPlayer będzie buforował dopóki nie zapełni swojego bufora maxBufferMs danymi multimedialnymi, następnie poczeka aż jego poziom spadnie do minBufferMs (dotyczy głównie VOD). Gdy poziom bufora spadnie poniżej minBufferMs danych medialnych, ExoPlayer zacznie ładować dane medialne ponownie, aż będzie miał bufor o wartości maxBufferMs danych medialnych. Takie burstowe zachowanie może prowadzić do problemów z rebufferingiem. Jest to domyślne zachowanie w ExoPlayerze v2.9.6 i wcześniejszych, ponieważ te wartości się różnią. W v2.9.6, minBufferMs ma domyślną wartość 15000 a maxBufferMs to 50000.
Aby jeszcze bardziej zmniejszyć szanse na rebuffering, zalecamy utrzymywanie dużego bufora w ExoPlayerze przez cały czas, poprzez ustawienie minBufferMs na taką samą wartość jak maxBufferMs. Ekipa ExoPlayera przeprowadziła eksperymenty i odkryła, że ustawienie minBufferMs na taką samą wartość jak maxBufferMs (i tym samym zmiana zachowania buforowania z bursty na drip-style) znacząco zredukowało liczbę zdarzeń rebufferingu, jednocześnie zwiększając tylko nieznacznie zużycie baterii. W rzeczywistości, począwszy od v2.10, ExoPlayer ma dla use-case’u video domyślny minBufferMs równy maxBufferMs i ustawiony na 50s.
Jak skonfigurować DefaultLoadControl używając DefaultLoadControl.Builder:
/* Instantiate a DefaultLoadControl.Builder. */
DefaultLoadControl.Builder builder = new
DefaultLoadControl.Builder();
/*Ilość milisekund danych multimedialnych do zbuforowania w dowolnym momencie. */
final long loadControlBufferMs = DefaultloadControl.MAX_BUFFER_MS; /* W ExoPlayerze 2.9.6 jest to 50000 milisekund */
/* Skonfiguruj DefaultLoadControl, aby używał tej samej wartości dla */
buildera.setBufferDurationMs(
loadControlBufferMs,
loadControlBufferMs,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS);
Summary
LoadControl jest punktem wejścia do strategii buforowania ExoPlayera. ExoPlayer posiada domyślną, ale konfigurowalną implementację interfejsu LoadControl, która powinna być wystarczająca dla większości przypadków użycia.
W oparciu o dotychczasowe dyskusje, poniżej znajduje się szybkie podsumowanie zaleceń:
- Aby zredukować czas startu, obniż wartość bufferForPlaybackMs; efektywnie, obniżając minimalną ilość danych multimedialnych buforowanych przed rozpoczęciem odtwarzania. Ma to wadę w postaci potencjalnego zwiększenia liczby zdarzeń buforowania.
- Aby zmniejszyć metrykę buforowania dla zawartości VOD, zwiększ wartość maxBufferMs; efektywnie zwiększając maksymalną ilość buforowanych danych medialnych. Jednakże pamiętaj, że może to negatywnie wpłynąć na urządzenia low-end.
- Aby zmniejszyć metrykę rebufferingu, ustaw minBufferMs i maxBufferMs na tę samą wartość. To zmieni zachowanie ExoPlayera z buforowania w stylu bursty na buforowanie w stylu drip.
Chcielibyśmy podziękować naszym kolegom Christianowi Worm Mortensenowi i Laustowi Brock-Nannestadowi za informacje zwrotne przy pisaniu tego posta.
W następnym wpisie na blogu, przyjrzymy się Strategii Wyboru Bitrate w ExoPlayerze. Bądźcie na bieżąco!