pl  |  en

Gdzie strumyk płynie z wolna czyli streaming z operacji serca.

Wiecie, że lubimy wyzwania. Dlatego kiedy zgłosiła się do nas zaprzyjaźniona agencja Bonjour z hasłem „robimy streaming operacji serca”, zgodziliśmy się od razu. Efekty tej współpracy oglądała cała Polska na stronie RMF 24.

Bieganiem z kamerami i kablami w rzeczywistym świecie to działka naszego partnera, my skupiliśmy się na dostarczeniu streamingu, który wytrzyma promocję w mediach. Do samego końca nie wiedzieliśmy, ile osób będzie oglądać tę transmisję, więc musieliśmy się przygotować na najlepsze.

źródło: rmf24.pl

Temat streamingu z daleka wygląda prosto, ale bliższy kontakt okazuje się gąszczem skomplikowanych protokołów, nieudokumentowanego oprogramowania i czyhających pułapek. Postanowiliśmy więc opisać naszą konfigurację od początku do końca i z czystym sumieniem stwierdzić „u nas działa” — bez użycia zamkniętego oprogramowania i systemów innych niż Linux.

W dzisiejszej transmisji to Bonjour i Outstanding Studios streamowali do nas, więc poniższy opis nie odzwierciedla dokładnie produkcyjnej konfiguracji — zamiast Linuksa i ffmpega klientem był Flash Media Live Encoder działający na Macu. Nasza konfiguracja testowa oraz konfiguracja serwerów wyglądała natomiast dokładnie tak, jak ją opisujemy.

Źródło sygnału

Do poważnych zastosowań, takich jak streaming operacji serca, spotkań Pykonika czy kotów Megi, używamy kamer ze złączem Firewire, ale transmisję wideo można zrealizować i na zwykłej kamerze USB, takiej jak wbudowana w wielu laptopach i jaką czasem można znaleźć w płatkach śniadaniowych. Na początek przejrzyjmy się w lustrze:

ffmpeg -f video4linux2 -i /dev/video0 -f sdl -

Po wykonaniu tego polecenia powinniśmy zobaczyć okno z obrazem z kamery. Możemy go zapisać np. do pliku w formacie Flash Video:

ffmpeg -f video4linux2 -i /dev/video0 -f flv hollywood.flv

Jest mały problem — nie ma dźwięku, bo video4linux to niestety nie video&audio4linux. Jest i rozwiązanie:

ffmpeg -f video4linux2 -i /dev/video0 -f alsa -i hw:0 -ar 44100 -f flv hollywood.flv

ffmpeg ma ogromną masę opcji do wpływania na wszystkie parametry filmu (może poza fabułą), dlatego nie będę nawet próbował ich tu przybliżyć. Powiedzmy, że rozdzielczość HD z kamery wielkości łebka od szpilki to to, czego aktualnie potrzebuję 🙂

Podmiana kamery na podłączoną po Firewire wymaga użycia dodatkowego narzędzia dvgrab, mimo że teoretycznie ffmpeg obsługuje Firewire bezpośrednio. Dane z dvgrab zawierają już dźwięk, więc najprostszy sposób na wygenerowanie Flash Video z obrazu z kamery wygląda mniej więcej tak:

dvgrab - | ffmpeg -i - -ar 44100 -f flv hollywood.flv

Serwer streamingu

Plik FLV można wrzucić na YouTube albo rozesłać linka do niego mailem, ale kłóci się to trochę z transmisją na żywo. Do tego jest potrzebny dedykowany serwer. Testowaliśmy najpopularniejsze — Red5 i crtmpserver. Oba oferują duże możliwości, ale niestety kuleją w kwestii dokumentacji. Flash Media Live Encoder dogadał się z crtmpserver bez problemu (w ten sposób nadawaliśmy relację z Pykonika i Geek Girls Carrots), ale żeby wysłać do niego obraz z ffmpeg, musieliśmy poeksperymentować. W końcu udało się:

dvgrab - | ffmpeg -i - -f flv -ar 11025 -metadata streamName=livestream rtmp://X.X.X.X/stream

Problemem jednak było uwierzytelnienie — ffmpeg nie mógł przekazać nazwy użytkownika i hasła, a niekoniecznie chcieliśmy umożliwiać streaming każdemu :). Prośby i groźby z użyciem Google’a, plików konfiguracyjnych a czasem i źródeł crtmpservera nie pomagały, więc ostatecznie z niego zrezygnowaliśmy. Red5 udało nam się zainstalować (pół gigabajta zależności…), po czym utknęliśmy na dłuższą chwilę wśród całego stada przykładowych aplikacji, które robiły wszystko tylko nie streaming wideo, niedziałających paneli administracyjnych i nieaktualnej dokumentacji. Musiał być jakiś prostszy sposób.

Na ratunek przyszedł nam nasz ulubiony serwer WWW — nginx. Okazuje się, że oprócz bycia proxy dla poczty, uniwersalnym proxy dla TCP i setką innych rzeczy, jest też prostym i skutecznym serwerem RTMP — czyli właśnie tego protokołu, którego potrzebujemy do streamingu na żywo.

Zainstalowaliśmy nginxa z tym modułem:

    wget https://nginx.org/download/nginx-1.2.5.tar.gz
    tar xzf nginx-1.2.5.tar.gz
    git clone git://github.com/arut/nginx-rtmp-module.git
    cd nginx-1.2.5
    ./configure --add-module=../nginx-rtmp-module
    make && make install

i skonfigurowaliśmy:

    user  www-data;
    worker_processes  1;
    rtmp_auto_push on;
    error_log logs/error.log notice;
    pid     /var/run/nginx.pid;
    
    events {
        worker_connections  1024;
    }
    
    rtmp {
        server {
            listen 1935;
            
            application stream {
                live on;
                allow publish X.X.X.X;
                deny publish all;
                allow play all;
            }
        }
    }

Sami byliśmy zaskoczeni, że streaming zadziałał od razu. Mieliśmy „tylko” problemy z flashowymi odtwarzaczami na stronie — mimo że odtwarzanie za pomocą vlc poszło gładko, ani JWPlayer, ani FlowPlayer nie widziały strumienia. Problem był równie ezoteryczny, co rozwiązanie proste. Pojedynczą transmisję RTMP opisuje nazwa aplikacji i strumień. O ile crtmpserver wymaga nazwy strumienia w metadanych:

dvgrab - | ffmpeg -i - -f flv -ar 11025 -metadata streamName=livestream rtmp://X.X.X.X/stream

o tyle nginx spodziewa się go w samym URLu:

dvgrab - | ffmpeg -i - -f flv -ar 11025 rtmp://X.X.X.X/stream/livestream

Tada. Poza tym, że nie mieliśmy pod ręką tyle łącza, żeby wystreamować obraz w oryginalnej jakości, więc trzeba było go przekodować do x264 przy 400 kbps i trochę zmniejszyć rozmiar klatki:

dvgrab - | ffmpeg -i - -ar 11025 -vcodec libx264 -b 400000 -vf scale=640:480 -f flv rtmp://X.X.X.X/stream/livestream

Dodajmy jeszcze w konfiguracji nginxa serwer plików statycznych (JWplayer i strona, w której jest osadzony) i statystyki liczby oglądających, generowanego transferu itp.:

    http {
        include       mime.types;
        default_type  application/octet-stream;
        
        sendfile        on;
        keepalive_timeout  65;
        
        server {
            listen       80;
            server_name  localhost;
            
            location / {
                root   html;
                index  index.html index.htm;
            }
            
            location /rtmpstats/ {
                rtmp_stat all;
                rtmp_stat_stylesheet /stat.xsl;
            }
            
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

To nie strumień, a mała powódź

Serwer, na którym stawialiśmy transmisję, ma do dyspozycji łącze 100 Mbps. Mimo że nie wiedzieliśmy, jakiej popularności się spodziewać, założyliśmy, że te 100 megabitów nie wystarczy. Przygotowaliśmy maszynę wirtualną w Oktawave (karty sieciowe po 10Gbps, nie udało nam się znaleźć rzeczywistego ograniczenia prędkości) i skonfigurowaliśmy ją jako proxy dla naszego streamingu.

    server {
        listen 1935;
         application stream {
            live on;
            pull rtmp://X.X.X.X pageUrl=example.com/index.html;
        }
    }

Dzięki temu mogliśmy serwować dane zarówno z naszego serwera, jak i z Oktawave. Już podczas transmisji sklonowaliśmy ją i po paru minutach mieliśmy dwa serwery streamingu z *dużym* łączem.

Ostatnim krokiem było ustawienie domenie, na którą łączył się flashowy odtwarzacz, wielu rekordów adresowych (po kilka na maszyny w Oktawave i pojedynczy rekord skierowany do naszego serwera), co pozwoliło na rozłożenie ruchu między serwery mniej więcej w oczekiwany sposób.

Operacja się udała, pacjent przeżył

Nie obyło się bez paru potknięć — trochę za późno zdecydowaliśmy o odciążeniu naszej maszyny, więc parę osób miało problemy z połączeniem, ale udało się to szybko naprawić.

A sama operacja? Pełen sukces 🙂 https://www.rmf24.pl/fakty/polska/news-nowatorska-operacja-serca-w-technice-3d-zakonczona-sukcesem,nId,716275.

Nagranie z przebiegu operacji jest już dostępne także na YouTube:

Autor: Grzegorz Nosek

  • Matias

    A uchylilibyście rąbka tajemnicy ile osób oglądało wasz strumień?

    • magdazarych

      Nie bardzo możemy 🙁 RMF na swoje stronie napisał, że kilkanaście tysięcy, ale trochę przesadzili.

  • Dyzio

    Jaki fajny techniczny artykulik! Dzieki i pozdrawiam 😉

  • laik

    No rewelacja !

  • Misiek

    Jaki program odpalony był na prawym Mac’u? Zna ktoś może ten soft?

    • magdazarych

      Hej

      Klient korzystał z Flash Media Live Encoder więc pewnie to, ale spróbuję jeszcze potwierdzić.

      • Misiek

        To wygląda jak jakiś video mixer, a FMLE nie ma żadnych ciekawych opcji w sobie. Zajmuję się streamingiem i właśnie szukam alternatyw różnych, bo jak ktoś pyta czym nadawać, to nie chcę się do 3-4 programów ograniczać.

        • magdazarych

          Z tego co udało mi się ustalić to to jest oprogramowanie do miksera Blackmagic Atem.

          • Misiek

            Tak, to jest to. Dzięki wielkie!

  • arjamizo

    >Ostatnim krokiem było ustawienie domenie, na którą łączył się flashowy odtwarzacz, wielu rekordów adresowych (po kilka na maszyny w Oktawave i pojedynczy rekord skierowany do naszego serwera), co pozwoliło na rozłożenie ruchu między serwery mniej więcej w oczekiwany sposób.

    można prosić więcej detali? Dzięki!

    • magdazarych

      Tutaj chodzi o przekierowanie domeny na adresy IP serwerów streamingu. Co chciałbyś wiedzieć, co jest niejasne?

      • arjamizo

        chodzi mi o to jakie komendy trzeba wpisać do terminala?

        • magdazarych

          Ustawienie w DNSach przekierowania na IP robisz na DNSach na które masz wydelegowaną domenę zapewne przez jakiś panel firmy, która Ci te DNSy udostępnia.

          • arjamizo

            oj, chyba będę musiał skontaktować się bezpośrednio z Panem Grzegorzem by poznać sekrety ukryte za tym jednym zdaniem w artykule 🙂

          • magdazarych

            Obawiam się, że Grzesiek ma mniej cierpliwości niż ja w ustalaniu co jest dla kogoś niezrozumiałe i tłumaczeniu jak przekierować domenę w DNSach (bo dokładnie o tym mówi to zdanie – o przekierowanie w DNSach domeny pod którą jest strona z playerem na IP serwerów streamingu).

          • arjamizo

            no tak, ale jak coś takiego zrobić? po prostu dodać kilka „równoważnych” rekordów i serwery same będą się „losować”?

          • magdazarych

            Dokładnie tak. Jak ktoś wejdzie na stronę z playerem i włączy streaming to jego lokalny resolver rozwiąże domenę, którą ten player ma podaną jako źródło streamingu, na IP. Którego serwera to będzie IP to już DNSy same „wymyślą”. Różni userzy będą dostawać losowe IP i w ten sposób ruch się rozłoży na wszystkie serwery. Tzw. loadbalancing na DNSach. Nie jest idealny, ale prosty i wystarczający w różnych sytuacjach.