Tutorial: Budowanie i sprawdzanie adresów RTSP kamer IP

Spis treści
Kamera IP przesyła obraz przez RTSP, a RTSP jest znormalizowany. Adres prowadzący do obrazu już nie. Każdy producent wymyślił własną ścieżkę, a kamera zapytana pod złą ścieżką odpowiada dokładnie tak samo jak przy złym haśle: wcale.
Taki adres składa się z sześciu części. Cztery wyglądają jednakowo w każdej kamerze, dwie trzeba sprawdzić u konkretnego producenta. Poniżej kolejność, w jakiej najlepiej te części złożyć, oraz jedno polecenie rozstrzygające, czy wynik działa – zanim trafi do rejestratora, gdzie błąd chowa się za sześcioma innymi ustawieniami.

Sześć części adresu strumienia
Adres RTSP jest zbudowany jak adres internetowy: schemat, dane logowania, host, port, ścieżka, a w części kamer jeszcze ciąg zapytania niosący numer strumienia.
rtsp://admin:Sommer%402026@192.168.1.64:554/Streaming/Channels/102
rtsp://admin:Sommer%402026@192.168.1.64:554/cam/realmonitor?channel=1&subtype=1
rtsps://192.168.1.1:7441/aBcD1234EfGh?enableSrtp
Schemat to rtsp, a port 554, dopóki nikt go nie przeniósł. Ubiquiti stanowi wyjątek wart zapamiętania: UniFi Protect odpowiada na rtsps na porcie 7441, odrzuca zwykłe RTSP i zamiast czytelnej ścieżki wydaje nieprzejrzysty identyfikator. Ten identyfikator pojawia się dopiero po włączeniu RTSP dla pojedynczej kamery w Protect.
Host oznacza kamerę, nigdy rejestrator. Rejestrator potrafi wystawić strumień ponownie, ale wtedy pod własnym adresem i na własnym porcie – a błąd na tej warstwie wygląda jak uszkodzona kamera.
Dlaczego ścieżka w każdej kamerze nazywa się inaczej
Ścieżka niesie dwie informacje, dla których sam RTSP nie ma pola: który obiektyw i który z jego strumieni. Niemal każda kamera oferuje co najmniej dwa – strumień główny w pełnej rozdzielczości do zapisu i podstrumień o czwartej części tej rozdzielczości do podglądu i analizy ruchu.
| Producent | Strumień główny | Podstrumień |
|---|---|---|
| Hikvision | /Streaming/Channels/101 | /Streaming/Channels/102 |
| Dahua, Amcrest | /cam/realmonitor?channel=1&subtype=0 | /cam/realmonitor?channel=1&subtype=1 |
| Reolink | /h264Preview_01_main | /h264Preview_01_sub |
| Axis | /axis-media/media.amp | /axis-media/media.amp?resolution=640×360 |
Numeracja Hikvision jest przekręcana najczęściej. Trzy cyfry to sklejone ze sobą kanał i strumień: z 1 oraz 01 powstaje 101, drugi strumień pierwszego kanału to 102. W kamerze z jednym obiektywem kanał zawsze wynosi 1; w obudowie z kilkoma matrycami drugi obiektyw nosi numery 201 i 202.
Zgadywanie staje się zbędne, gdy kamera obsługuje ONVIF. Wywołanie GetStreamUri zwraca adres, który sama kamera uważa za poprawny, wraz ze ścieżką – a ta odpowiedź bije każdą tabelę.
Hasła, które rozbijają adres
Dane logowania stoją między schematem a hostem, oddzielone dwukropkiem i zamknięte znakiem małpy. Właśnie tam siedzi najcichszy błąd: hasło zawierające małpę, dwukropek, ukośnik lub krzyżyk kończy dane logowania za wcześnie, a reszta hasła zostaje odczytana jako nazwa hosta.
Lekarstwem jest kodowanie procentowe. Małpa zamienia się w %40, dwukropek w %3A, ukośnik w %2F, krzyżyk w %23, znak zapytania w %3F. Hasło Sommer@2026 pojawia się więc w adresie jako Sommer%402026 i pozostaje w kamerze niezmienione.
Do drugiej strony tej sprawy należy uwaga: wiele kamer uwierzytelnia się przez RTSP digest, a nie przez Basic Auth. Hasło nie wędruje zatem przez sieć otwartym tekstem, choć otwartym tekstem stoi w adresie. Otwartym tekstem wędruje natomiast sam adres – w historii powłoki, w pliku Compose, w linii dziennika. Dane logowania do kamery należą więc do osobnego konta z samym prawem podglądu, nigdy do konta administratora.
Sprawdzenie adresu, zanim gdziekolwiek trafi
Jedno polecenie odpowiada na jedyne pytanie, które na tym etapie się liczy. Otwiera strumień, czyta pierwsze pakiety, wypisuje znalezione dane i kończy pracę.
ffprobe -hide_banner -rtsp_transport tcp \
-i "rtsp://admin:Sommer%402026@192.168.1.64:554/Streaming/Channels/102"
Działający adres w ciągu sekundy lub dwóch wypisuje linię strumienia z kodekiem, rozdzielczością i liczbą klatek. Wszystko inne jest diagnozą, a cztery częste odpowiedzi wskazują w cztery różne strony.
| Odpowiedź | Znaczenie |
|---|---|
| 401 Unauthorized | Host i ścieżka są poprawne, dane logowania nie – albo konto nie ma prawa do strumienia |
| 404 Not Found | Dane logowania przyjęte, ścieżka błędna – o jednego producenta albo jeden numer strumienia obok |
| Connection refused | Na porcie 554 nic nie nasłuchuje; RTSP wyłączone w kamerze albo port przeniesiony |
| Przekroczenie czasu po handshake | Sesja stoi, pakiety wideo nie docierają – niemal zawsze zablokowany UDP |
Ostatnia z czterech tłumaczy, dlaczego w poleceniu stoi -rtsp_transport tcp. Domyślnie kanał sterujący biegnie przez TCP, a obraz przez UDP na osobnych portach. Przez granicę VLAN albo przez zaporę handshake dochodzi więc do skutku, a obraz mimo to nigdy nie przychodzi. Wymuszony TCP kosztuje trochę opóźnienia i usuwa całą klasę usterek.
Który strumień gdzie należy
Gdy adres już działa, podstrumień okazuje się pożyteczniejszą połową. Zapis potrzebuje strumienia głównego, bo to ten materiał ogląda ubezpieczyciel albo sąd. Analiza ruchu i wykrywanie obiektów potrzebują małych obrazów i z nimi przyspieszają: detektor karmiony klatkami 4K spędza czas na ich pomniejszaniu.
Frigate wyraża ten podział wprost, przypisując rolę każdemu strumieniowi – ta sama myśl dotyczy każdego rejestratora przyjmującego dwa wejścia na kamerę.
cameras:
wjazd:
ffmpeg:
inputs:
- path: rtsp://admin:Sommer%402026@192.168.1.64:554/Streaming/Channels/102
input_args: preset-rtsp-generic
roles: [detect]
- path: rtsp://admin:Sommer%402026@192.168.1.64:554/Streaming/Channels/101
input_args: preset-rtsp-generic
roles: [record]
Dwa połączenia do jednej kamery bywają zarazem górną granicą. Tanie kamery dopuszczają cztery równoczesne sesje RTSP, czasem tylko dwie, a piąta próba kończy się komunikatem niemającym nic wspólnego z adresem. Restreamer taki jak go2rtc rozwiązuje to, otwierając jedną sesję i rozdając kopie pozostałym.
Co i tak psuje się później
Adres, który raz zadziałał, potrafi przestać działać, choć nic się w nim nie zmieniło. Trzy przyczyny obejmują niemal wszystko.
Pierwsza to DHCP. Kamera adresowana wypożyczonym IP wędruje po restarcie routera, a adres wskazuje na to, co przejęło numer. Rezerwacja na serwerze DHCP albo stały adres w samej kamerze kończy to na trwałe.
Druga to aktualizacja oprogramowania, która resetuje przełącznik RTSP albo konto podglądu. Oba warto sprawdzić po aktualizacji w pierwszej kolejności, bo objaw – najpierw Connection refused, potem 401 – wygląda na usterkę sieci.
Trzecia to czas. Wiele kamer porzuca sesję leżącą bez informacji zwrotnej RTCP, a część rejestratorów nigdy jej nie wysyła. Wygląda to tak: strumień działa godzinami i znika w nocy, za każdym razem o nieco innej porze. Restreamer z ponownym łączeniem usuwa objaw, a odstęp keepalive poniżej progu czasowego kamery usuwa przyczynę.
Pytania i odpowiedzi
Czy detekcja obiektów na podstrumieniu znajduje także osoby, które są daleko?
Tylko dopóki mają tam jeszcze dość pikseli, a to da się policzyć. Podstrumień o czwartej części rozdzielczości ma czwartą część pikseli, ale połowę pikseli na metr, bo ich liczba spada o połowę w obu kierunkach. Wiele kamer daje w podstrumieniu jeszcze mniej, na przykład 640 × 360 jak w przykładzie Axis z tabeli; w porównaniu ze strumieniem głównym 4K to jedna szósta gęstości.
Przykład z kamerą 4K, matrycą 1/2,8 cala i obiektywem 2,8 mm: w odległości 20 metrów strumień główny daje 96 pikseli na metr, a podstrumień o szerokości 640 pikseli – 16. Osoba o wzroście 1,80 metra ma tam niecałe 29 pikseli wysokości, w strumieniu głównym byłoby to ponad 170. Podstrumień 1280 × 720 podwaja tę wartość do około 58 pikseli.
Jeśli detekcja pomija osoby na dalekim końcu sceny, w pierwszej kolejności należy więc sprawdzić rozdzielczość podstrumienia, a dopiero potem detektor. Strumień główny zostaje do zapisu; podstrumień powinien być na tyle duży, by najdalsze miejsce, w którym coś ma jeszcze zostać wykryte, dostało dość pikseli.
Jak utrzymać dane logowania poza konfiguracją Frigate?
Frigate wstawia do konfiguracji zmienne środowiskowe, o ile ich nazwa zaczyna się od FRIGATE_. W adresie stoi wtedy symbol zastępczy w rodzaju {FRIGATE_RTSP_PASSWORD}, a wartość pochodzi z pliku środowiskowego o ograniczonych uprawnieniach, który nie jest przekazywany ani wersjonowany razem z konfiguracją. Wartość zostaje wstawiona dokładnie w takiej postaci, w jakiej jest zapisana, więc małpa w haśle także w zmiennej musi mieć postać %40.
Ta sama zasada dotyczy sprawdzania przez ffprobe: adres nie powinien trafiać do wiersza, który zachowuje historia powłoki. W Bashu spacja na początku polecenia zapobiega zapisowi, jeśli HISTCONTROL ma wartość ignorespace lub ignoreboth, jak domyślnie w Debianie i Ubuntu. Najważniejszym środkiem pozostaje mimo to osobne konto z samym prawem podglądu, bo gdzieś adres zawsze stoi otwartym tekstem.
Które znaki oprócz @, :, /, # i ? również trzeba zakodować?
Przede wszystkim sam znak procentu, jako %25, bo inaczej parser odczyta znak procentu z dwiema następującymi po nim cyframi szesnastkowymi jako kod; spacja zamienia się w %20. Te same zasady dotyczą nazwy użytkownika, w której szczególnie przeszkadza dwukropek, bo pierwszy dwukropek oddziela nazwę od hasła.