Frontend

Jak stworzyć własny live streaming

Sukces Netfliksa, Youtube’a czy Twitcha sprawił, że jak grzyby po deszczu pojawiły się inne serwisy streamingowe. Według statystyk ponad połowę wygenerowanego ruchu w Internecie stanowią treści wideo. Czy wiesz jednak w jaki sposób wideo trafia do Twojej przeglądarki? W tym artykule pokażę w jaki sposób skonfigurować własny streaming treści na żywo.

Artykuł podzieliłem na trzy części:

  • kilka słów o tym czym jest standard DASH,
  • przygotowanie materiału do streamowania na żywo,
  • osadzenie i konfiguracja playera na stronie www.

Wojciech Morkowski. Front-end developer, miłośnik Reacta.
Na co dzień pracuje w Insysie, gdzie rozwija aplikacje www oraz smart tv związane z wideo streamingiem. Zwolennik automatyzacji powtarzalnych czynności. W wolnych chwilach zajmuje się pielęgnacją sadu.


Standard DASH

Akronim DASH oznacza Dynamic Adaptive Streaming over HTTP. Standard ten definiuje sposób streamowania treści wideo przez Internet. DASH pozwala na zmianę parametrów wideo w trakcie jego odtwarzania — stąd właśnie dynamic w nazwie. Adaptive określa możliwość dostosowywania parametrów wideo np. na podstawie parametrów łącza lub obciążenia procesora.

Takie zachowanie możesz zauważyć na przykład na youtube, gdy włączysz odtwarzanie filmu w automatycznym trybie doboru jakości i równolegle zaczniesz pobierać plik. W takiej sytuacji przeglądarka nie będzie mogła wykorzystać całej przepustowości łącza do odbioru streamingu. Player, by zachować płynność odtwarzania, zmieni jakość odtwarzanego filmu. Możesz zauważyć wtedy, że jakość zmniejszy się przykładowo z 720p do 480p. Gdy wstrzymasz pobieranie, jakość powinna wrócić do wyższej wartości. Oto strategia działania — dobrać maksymalną jakość odtwarzania z zachowaniem płynności.

Jak to się dzieje, że możliwa jest zmiana jakości?

Materiał wideo zostaje podzielony na mniejsze części zwane segmentami. Każdy z segmentów ma określony czas trwania. Dla każdego segmentu generowane są alternatywne segmenty, o innych parametrach (np. innej rozdzielczości).

Mówiąc inaczej — pobieramy film lub materiał na żywo “po kawałku” i w razie potrzeby przełączamy się pomiędzy różnymi wariantami tych kawałków.

Parametry streamingu dla standardu DASH opisane są w manifeście — pliku o rozszerzeniu mpd. Ścieżkę do tego pliku podajemy playerowi jako źródło. W manifeście możemy odczytać informacje takie jak użyte kodeki, wysokości i szerokości obrazu, liczbę klatek na sekundę, bitrate. Podczas streamingu treści na żywo, manifest jest na bieżąco odświeżany, tak by zawierał określoną liczbę najnowszych segmentów.

Przygotowanie plików multimedialnych za pomocą programu ffmpeg

Teorię mamy już za sobą, pora na praktykę. Kilka słów na temat tego co będziemy robić. Dla uproszczenia całego przykładu wideo streamingu, przyjąłem kilka założeń:

  • będziemy przechwytywać obraz aktualnie wyświetlany na ekranie,
  • nie będziemy przechwytywać dźwięku,
  • streaming będzie dostępny w dwóch jakościach (wysokiej i niskiej),
  • pliki multimedialne będziemy udostępniać w obrębie sieci lokalnej.

Pierwsza rzecz to pobranie programu ffmpeg. Opis instalacji można znaleźć tu. Jeżeli korzystasz z Windowsa, to warto zwrócić uwagę na sekcję z dodaniem ffmpega do ścieżki systemowej PATH.

Kolejne kroki odnoszą się do Windowsa, ale na repozytorium znajdziesz skrypty dla Linuksa (Linuks używa innego urządzenia przechwytującego).

Stwórz plik wsadowy encode.bat

W utworzonym pliku wpisz:

ffmpeg ^
   -f gdigrab ^
   -r 30 ^
   -i desktop ^
   -map 0 ^
   -map 0 ^
   -b:v:0 1000k ^
   -b:v:1 256k ^
   -s:1 400x300 ^
   -codec:v libx264 ^
   -profile:v baseline ^
   -level 4 ^
   -pix_fmt yuv420p ^
   -preset veryfast ^
   -f dash ^
   -window_size 5 ^
   -remove_at_exit 1 ^
   -adaptation_sets "id=0,streams=0 id=1,streams=1" ^
   public/media/live.mpd

Będzie to plik startowy dla ffmpega, uruchamiający przechwytywanie obrazu i jego konwersję. Co oznaczają poszczególne flagi ffmpega?

  • f gdigrab — wskazuje, że urządzeniem wejściowym będzie gdigrab, windowsowe, wirtualne urządzenie do przechwytywania obrazu,
  • i desktop — określa obszar przechwytywania (w tym przypadku cały ekran, ale można też przechwytywać obraz tylko z konkretnego okna),
  • r 30 — określa liczbę klatek na sekundę,
  • map 0 — to nie pomyłka, podwójny wpis map pojawia się celowo. W ten sposób mówimy ffmpegowi, że ze strumienia wejściowego 0 (gdigrab generuje jeden strumień), chcemy uzyskać dwa strumienie wyjściowe,
  • b:v:0 1000k — zapis oznacza, że strumieniowi wyjściowemu video o identyfikatorze 0 ustalamy bitrate na 1000 000 bitów/s (strumień o wyższej jakości),
  • b:v:1 256k — zapis oznacza, że strumieniowi wyjściowemu video o identyfikatorze 1 ustalamy bitrate na 256 000 bitów/s (strumień o niższej jakości),
  • s:1 640x360 — oznacza, że drugi strumień wyjściowy zostanie przeskalowany do niższej rozdzielczości,
  • codec:v libx264 — określa jakim kodekiem chcemy zakodować oba strumienie wideo. Wybieramy taki kodek, by móc odtwarzać wideo na jak największej liczbie przeglądarek,
  • rofile:v baseline oraz -level 4 to parametry powyższego kodeka, określają jaką klasę urządzeń chcemy obsługiwać (te opcje oznaczają że obsługujemy też starsze urządzenia),
  • pix_fmt yuv420p — parametr kodeka, format pikseli — określa sposób zapisu koloru,
  • preset veryfast — parametr kodeka, zbiór opcji mówiący jak szybko ma być wykonywane kodowanie (im szybsze kodowanie, tym gorszy stopień kompresji),
  • f dash — określa format wyjściowy (zamiast DASHa mógłby się tu znaleźć np. format HLS),
  • window_size 5 — parametr DASHa, określa ile segmentów może maksymalnie znajdować się w manifeście,
  • remove_at_exit 1 — parametr dasha, wymusza usunięcie plików multimedialnych po zakończeniu działania programu,
  • adaptation_sets "id=0,streams=0 id=1,streams=1" — parametr DASHa, określa jak przekazać strumienie wyjściowe,
  • public/media/live.mpd — określa plik wyjściowy.

Po utworzeniu pliku startowego utwórz folder public (będzie to folder, w którym znajdą się serwowane pliki statyczne), a w folderze public utwórz folder media (będą się tam znajdować pliki multimedialne). Jeżeli uruchomisz Twój plik startowy, to powinieneś zobaczyć logi ffmpega. Po chwili, w folderze media, powinieneś zobaczyć plik manifestu oraz pliki segmentów (w dwóch różnych wariantach stream0 i stream1, dla dwóch różnych jakości).

Osadzenie playera na stronie

Ostatni krokiem będzie osadzenie playera na stronie www. W tym celu skorzystamy z Shakaplayera rozwijanego przez Google. Dlaczego jest nam potrzebny player? DASH nie jest natywnie obsługiwany w przeglądarkach innych niż MS Edge. Użyjemy shakaplayera, by mieć możliwość odtwarzania naszego strumienia na innych przeglądarkach.

W folderze public stwórz dwa pliki — index.html i player.js

Tak powinien wyglądać index.html:

<!DOCTYPE html>
<html>
<head>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/shaka-player/2.4.5/shaka-player.compiled.js"></script>
   <script src="./player.js"></script>
</head>
<body>
   <video id="video" width="640" controls autoplay></video>
   <button id="auto">Auto Quality</button>
   <button id="0">High Quality</button>
   <button id="1">Low Quality</button>
</body>
</html>

W head osadzamy Shakaplayera oraz plik player.js, gdzie znajdzie się kod inicjalizujący playera. W body definiujemy tag video, pod który podpinać będziemy playera oraz trzy przyciski, które będą sterować jakością odtwarzania.

Przejdźmy teraz do pliku player.js.

Bazą naszego przykładu niech będzie zmodyfikowany example ze strony playera:

(function () {
 const manifestUri = 'media/live.mpd';

 function initApp() {
     shaka.polyfill.installAll(); // kod instalujący polyfille 
// potrzebne, by player działał na różnych przeglądarkach

     if (shaka.Player.isBrowserSupported()) {
         initPlayer();
     } else {
         console.error('Browser not supported!');
     }
 }

 function initPlayer() {
     const video = document.getElementById('video');
     const player = new shaka.Player(video);

     window.player = player;
     player.addEventListener('error', onErrorEvent);
     player.load(manifestUri).then(function () {
         console.log('The video has now been loaded!');
     }).catch(onError);
 }

 function onErrorEvent(event) {
     onError(event.detail);
 }

 function onError(error) {
     console.error('Error code', error.code, 'object', error);
 }

 document.addEventListener('DOMContentLoaded', initApp);
})();

Ten kod pozwala na odtworzenie live streamingu przez playera, jednak brakuje tu jeszcze jednej rzeczy. Shakaplayer nie dostarcza żadnej kontrolki pozwalającej na ręczną zmianę jakości. Dlatego też w pliku index.html stworzyliśmy trzy przyciski. Teraz pozostaje nam je oprogramować.

Stwórzmy handler, który ma obsłużyć kliknięcie przycisków:

   function handleChangeQuality(event) {
       const buttonId = event.target.id;
       if (buttonId === 'auto') {
           window.player.configure({ abr: { enabled: true }});
           return;
       }

       window.player.configure({ abr: { enabled: false }}); // wyłączenie automatycznej zmiany jakości
       const variantTracks = player.getVariantTracks();
       window.player.selectVariantTrack(variantTracks[parseInt(buttonId)]); 
   }

Domyślnie Shakaplayer dostosowuje jakość automatycznie, dlatego też przy kliknięciu przycisku wysokiej lub niskiej jakości należy tę funkcję wyłączyć poprzez zmianę flagi abr (adaptive bitrate) na false. Ręczna zmiana jakości polega na wybraniu jednej opcji z tablicy zwracanej przez metodę getVariantTracks(). Tablica ta dla naszego przykładu będzie wyglądać tak:

Będzie się ona składać z dwóch obiektów, jak widzisz na powyższym screenie pierwszy obiekt będzie odpowiadał strumieniowi o większej jakości (większa rozdzielczość i bitrate).

Teraz wystarczy tylko podpiąć handler pod przyciski:

       player.load(manifestUri).then(function () {
           console.log('The video has now been loaded!');
           document.getElementById('auto').addEventListener('click', handleChangeQuality);
           document.getElementById('0').addEventListener('click', handleChangeQuality);
           document.getElementById('1').addEventListener('click', handleChangeQuality);
       }).catch(onError);

Ostatni krok to serwowanie plików statycznych. Jako serwera plików statycznych użyjemy serve. Stwórz plik package.json (komenda npm init), a następnie pobierz paczkę z serwerem (npm install serve). Na koniec dodaj odpowiednie skrypty do package.json czyli:

 "scripts": {
   "start": "serve public",
   "encode": "encode.bat"
 }

W dwóch konsolach uruchom oba skrypty komendami npm run start oraz npm run encode. Wpisz w przeglądarce adres http://localhost:8080/ lub Twój adres w sieci lokalnej i ciesz się Twoim własnym wideo streamingiem!

Jeżeli przyjrzysz się requestom jakie wysyła przeglądarka, to zauważysz, że po kliknięciu zmiany jakości, pobierane są segmenty, które wskazują na różne strumienie (stream0 i stream1), segmenty większej jakości mają zauważalnie większy rozmiar, a zmiana jakości jest widoczna!

To już wszystko. Wspólnie stworzyliśmy Twój pierwszy, własny live streaming! Kody źródłowe dla tego artykułu znajdziesz tutaj. Jeżeli zainteresował Cię temat i chciałbyś razem z nami tworzyć telewizję przyszłości to serdecznie zapraszam do rekrutacji.

Wszystkim tym, którzy chcieliby poszerzyć swoją wiedzę na temat live streamingu polecam linki:


najwięcej ofert html

Zdjęcie główne artykułu pochodzi z pexels.com.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://geek.justjoin.it/jak-stworzyc-wlasny-live-streaming/" order_type="social" width="100%" count_of_comments="8" ]