Почему рассыпается картинка с IP-камеры?
В подавляющем большинстве недорогих IP-камер (стоимостью до 30 тыс рублей) практически идентичный код прошивки, и почти везде встречается одна и та же проблема в сетевом стеке.
Эта проблема выражается в том, что качество получаемой картинки начинает зависеть от сетевых условий. Выглядит это явление так: в офисе при просмотре через VLC картинка хорошая, а когда камеру вешают на уличный столб — при просмотре через Flussonic картинка рассыпается.
Аналогично может быть при проверке работы камеры через родное приложение: в нём всё идеально, в Flussonic рассыпается.
Технические детали
Проблема кроется в одном и том же баге, существующем в одном и том же коде, используемом в большинстве камер, сделанных в Китае: поставщик прошивки один.
ПО на камере при вещании по TCP RTSP переводит сетевой сокет в неблокирующий режим. В этом режиме
Linux будет копировать в выходной буфер сокета столько данных, сколько может, но не больше, чем
осталось места в буфере. В неблокирующем режиме программа не засыпает на время отправки данных по сети
(и это в целом правильно, что бы не терять кадры с сенсора), вместо этого функция write
будет возвращать количество записанных байт, которое может быть меньше, чем программа попросила отправить в сеть.
Т.е. RTSP стример готовит пакет для отправки по UDP или TCP, пытается отправить по TCP примерно 1500 байт, но записывается только 300 байт. Чтобы данные отправились правильно, программа должна запомнить этот факт и допослать данные позже.
Проблема с китайскими камерами заключается в том, что в них используется старый код live555 сервера примерно 2005 года, в котором нет такой логики, и камера просто выбрасывает недоотправленные данные. Т.е. в программе на камере неверная реализация сетевой логики.
Пакет начинает слаться по сети, идет его заголовок, в котором написано: 1450 байт длина, дальше идет 300 байт и начинается следующий пакет. Таким образом достигается удивительное поведение: данные передаются по TCP и теряются.
Клиент, реализованный по стандарту, в этом месте сбивается, видит что дальше идет мусор и закрывает соединение.
Клиент, реализованный со знанием этих проблем, тратит много CPU на поиск таких проблем, детекцию такого срыва потока. Вернуть потерянные данные он не может и видео рассыпается.
Если вы хотите посмотреть, когда это происходит, то посмотрите в tcpdump: как только приходит сигнал о закрытии приемного буфера, сразу рассыпается картинка.
В случае использования приложения, поставляемого с камерой, вы используете не RTSP, а свой собственный протокол, с соединением на другом порту. На качество его работы китайские инженеры обращают больше внимания, поэтому через него картинка лучше.
Сопутствующие проблемы
Несложно догадаться, что больше всего будет таких потерь при передаче опорных кадров: они больше и больше вероятность что хотя бы одно рассыпание попадет на такой кадр, а так же при посылке опорного кадра растет трафик передачи по сети и быстрее забиваются выходные буферы.
Результат этого такой, что видео никогда не приходит в норму, потому что опорные кадры внизу постоянно рассыпанные, смазанные.
Как с этим бороться
На сервере мало что можно сделать с этой проблемой. В Flussonic реализовано несколько методик борьбы с этой проблемой: большие приемные буферы, восстановление разрушенного потока и т.п.
Надо очень тщательно разбираться с сетью: не допускать перегрузок, бороться с микровсплесками, постараться избежать радиолинков.
Агент на камере
Самое действенное решение — это агент на камере. Очень важно, что бы L2 транспорт поменялся на L7, чтобы камере никогда не приходило сообщение о закрытии буфера.
Наш агент написан так, что он всегда примет данные от камеры и, следовательно, ничего не потеряет.
Аналогичный эффект будет при использовании других подобных решений или проброса портов через ssh.