Почему рост качества вызывает рост некачества, или должна ли работать основная функция



Глупо спорить с тем, что аналоговое видеонаблюдение уходит в прошлое: дешевые IP камеры дают картинку сопоставимого качества с дорогими аналоговыми. Помимо этого, IP камеры не ограничены сверху ничем, кроме производительности регистратора, тогда как аналоговые камеры требуют жесткого соответствия приёмной карты, согласования уровней сигнала передатчиков/усилителей/приемников и прочего шаманства.
Конструируя систему на базе IP камер в любой момент можно снять камеру и заменить на более качественную — если при этом сохранить IP адрес и логин-пароль, то, скорее всего, даже не придётся менять настройки приемника — просто в архив пойдёт более качественная картинка.
С другой стороны, это накладывает ограничения на регистратор — он должен быть готов работать с любым разрешением, любым битрейтом, любым кодеком и любым протоколом… Ну или по крайней мере, корректно работать с заявленным.



В мире софта есть два пути — есть linux-way: это набор небольших программ, каждая из которых делает одну функцию, но очень хорошо; и есть windows-way: это огромные кухонные комбайны, которые умеют делать всё, и немного больше. Главная проблема linux-way — это отсутствие интерфейса. Чтобы получить всю пользу придётся скурить маны (или хотя бы прочитать --help), и поэкспериментировать. А так же сообразить, что и с чем можно скомбинировать и как. Главная проблема windows-way — это потеря основной функции. Очень быстро при обрастании доп.функционалом теряются тесты ключевого функционала, и со временем начинаются проблемы даже с ним. А еще при этом начинается инерция мышления: «это главная функция, она оттестирована сильнее всего, там бага быть не может, пользователь делает что-то не то».

Теперь переходим к нашим баранам: сейчас идёт постоянный рост качества IP камер. Любой, кто видел разницу FullHD камеры, установленной на том же месте, где до этого стояла даже ультракрутая 700TVL, уже не захочет вернуться назад (тем более, что по цене сейчас это уже примерно одинаково). Дальнейшее развитие приводит к тому, что камеры 3MP (2048x1536) и 5MP (2592x1944) уже не редкость. Единственная цена за повышенное качество — возрастающие затраты на хранение и передачу. Однако цена гигабайта на жестком диске уже давно падает (и вполне оправилась от потопа на заводе), а потому не является проблемой.

Буквально сегодня был небольшой спор с maxlapshin на тему должен ли производитель софта чего-либо пользователю, после продажи, или нет. Да, любой софт продаётся «как есть» без каких-либо обещаний. Поэтому даже заплатив сколько бы то ни было, вы не факт что получите даже рабочий софт. Вот только если софт не работает, и это известно — поток покупателей иссякнет в один прекрасный момент. Хотя пока покупают, очевидность исправления ошибок (а уж тем более, реализация фич) под большим вопросом.

Закончим вступление, и посмотрим небольшое, но очень показательное видео (можно даже не смотреть — на стоп.кадре всё видно):


Это хрестоматийный глюк, который я наблюдаю практически на всём ПО, предназначенном для видеорегистрации. Я видел это на VideoNet, вижу регулярно на Axxon Next, как видите на видео — этим меня поприветствовал Trassir. Та же байда даже в родном просмотрщике камеры. Можно бы и списать все проблемы на камеру. Можно списать на сеть. Можно на высокую нагрузку на CPU. Можно на электромагнитные помехи. Можно посоветовать проверить память. Можно переустановить систему. В общем, способов вместо разбирательства заставить человека принести унитаз
Вот только подключаясь к тому же rtsp потоку через vlc никаких артефактов и сбоев — нет. На том же компьютере я запускаю наколенный тест-скрипт, который читает из камеры поток и пишет на диск — и никаких потерь и проблем нет, а потому работает только один метод — снижать разрешение камеры и снижать битрейт.

То есть несмотря на гибкость, заявленную поддержку кучи камер, работу по ONVIF и RTSP… Всё равно можно не получить никаких плюсов от IP наблюдения, так как принимающий софт оказался не готов к этому.

Основной причиной такого поведения, как ни странно, является IP сеть, кодеки, и… канализация.

Итак, для начала, краткая базовая теория по IP сети. В сети всё бегает в форме пакетиков. У каждого пакета есть максимальный размер (MTU, 1500 на обычных линках), отправитель и получатель. Пакетик как-то там по пути пересылается и в итоге должен добраться до получателя. Может не добраться. Может порезаться. Может придти кусочек… В общем, возможны варианты. Из этих пакетиков сверху накручивают транспортные протоколы: UDP и TCP (из интересующих нас). На UDP ничего не меняется, только появляется порт отправителя и порт получателя, чтобы можно было пакеты разделять между собой; а на TCP наворачивается куча логики, которая «гарантирует доставку». Точнее — гарантирует доставку или генерацию ошибки, если что-то не может быть доставлено. Ну как гарантирует… обещает (обещать — не значит жениться ;) Любой админ многократно видел «зависшие» соединения, на том же мобильном инете, например).

Как TCP гарантирует доставку? А просто — каждый пакет должен получить подтверждение. Нет подтверждения в течение некоего времени — пакет потерян — переотправим его. Но если на каждый пакет ждать подтверждения — скорость упадёт чудовищно, и тем больше, чем выше задержка между общающимися точками. Поэтому вводится понятие «окна» — мы можем отправить максимум N пакетов без подтверждения, и только потом ждать подтверждения. Но ждать N подтверждений тоже много — приёмник тоже будет принимать и посылать подтверждения не на каждый, а просто «максимальный виденный». Тогда подтверждений меньше. А еще подтверждение можно посылать вместе с отправляемым пакетом, чтоб два раза не вставать. В общем — логики море, вся направлена на исполнение обещания доставки, но при этом максимальной утилизации канала. Размер окна — величина непостоянная, и выбирается системой исходя из магии вуду, настроек, погоды на марсе. Плюс, меняется в процессе работы потока. Этого момента коснёмся чуть позже.

Итак, теперь перейдём к нашим баранам — H264 поверх RTSP. (На самом деле, это практически неважно — что за кодек и что за транспортный протокол. Не думайте, что если вы используете какой-либо свой гениальный протокол, который в разы проще RTSP, что это вас не касается). Поток состоит из периодически повторяющегося ключевого кадра, и потока изменений относительно текущего состояния. Подключаясь к видео надо дождаться ключевого кадра, после чего мы берём его за текущее состояние, и далее принимаем диффы, которые накладываем и показываем. Что это значит? Это значит, что раз в X секунд прилетает МНОГО данных — полный кадр. И тем больше, чем выше разрешение камеры и чем выше битрейт (хотя, будем честными, битрейт слабо влияет на размер кейфрейма). Итак, вот у нас момент времени 0 — начало ключевого кадра, при котором прилетает сразу полный кадр (допустим, у нас камера все 3 мегаписеля — это 2048x1536 = 3145728 пикселей. После сжатия это жалких ~360 килобайт). Всего поток у нас 8 мегабит = 1 мегабайт, кейфрейм раз в 5 секунд, а FPS=18. Тогда у нас будет нечто типа 360к, затем по 52к каждые 1/18 секунды, спустя 5 сек опять 360к, потом опять по 52к.

Теперь опять вернёмся к UDP и TCP. Пришедший на сетевую карту пакетик складывается в буфер сетевой карты, и процессору ставится флаг (или вызывается прерывание) что есть данные. Процессор приостанавливает исполнение всего полезного, достаёт из карты пакет, и начинает подъём и раздевание его по TCP/IP стеку. Этот процесс выполняется на высочайшем приоритете (ибо работа с железом). Но у нас всё-таки винда или линукс, ни то ни то не RTOS, поэтому нет никаких гарантий, когда именно приложение сможет добраться до этого пакета. А посему, как только система разобралась что это за пакет, к какому соединению относится, пакет пытается уложиться в буфер.
На UDP: если места в буфере нет, пакет выкидывается.
На TCP: если места в буфере нет, включается алгоритм управления потоком — отправителю посылается сигнал переполнения, мол заткнись, пока я тут не освобожусь немного. Как только приложение забирает часть данных из буфера, система отправляет «ОК, погнали дальше» отправителю, общение возобновляется.

Теперь давайте сложим всё, и распишем как происходит приём данных от камеры. Для начала — простой случай, на UDP. Камера считывает следующий кадр, засовывает его в сжиматель, из сжимателя достаёт сжатые данные, режет на пакетики, добавляет заголовки и отправляет получателю. Получатель сперва получает 260 UDP пакетов, потом пауза, еще 40 пакетов, пауза, еще 40 пакетов и т.д. Первые 260 UDP пакетов прилетают моментально — за где-то 30 миллисекунд; а уже на 55й миллисекунде прилетают следующие 40 (за еще 4 миллисекунды). Допустим, буфер у нас стоит 128 килобайт. Тогда, они забьются за 10 миллисекунд. И если за это время приложение буфер не опустошит в едином вычитывающем всё порыве (а на деле читают за раз по одному пакету...) — мы потеряем остаток ключевого фрейма. Учитывая, что у нас не RTOS, и приложение может принудительно «заснуть» по любой из причин (например, пока ОС сбрасывает буфера на диск) на ту же секунду, единственный способ ничего не терять — нужно иметь сетевой буфер размером больше, чем мы можем спать. То есть в идеале буфер ОС нужно устанавливать равным ~2 секундам потока, в данном случае — 2 мегабайта. Иначе потери гарантированы.



О'кей, но у нас же есть TCP! Который гарантирует доставку, и попросит подождать отправителя если что! Давайте переключимся на TCP, и посмотрим на ту же картину. Дополнительным оверхедом можно пренебречь, просто давайте посмотрим, что происходит. Итак, у нас вылетает 360 килобайт данных. Они отправляются по 100мбит каналу где-то 30 миллисекунд. Где-то на 10й миллисекунде буфер приёмника переполнился, и камеру попросили помолчать. Допустим, спустя еще 20мс приложение прочитало весь доступный буфер (а на деле — прочитало 4 байта, затем 1400, затем еще 4, еще 1400...), и ОС попросило камеру продолжать. камера отправила еще треть кейфрейма и опять заткнулась. Спустя еще 20мс поехали дальше — но камера произвела еще данных, которые легли в буфер самой камеры. И тут мы подходим к скользкому моменту — а какой размер TCP буфера в камере? К тому же, из-за постоянных «заткнись»-«продолжай» эффективная пропускная способность сети падает катастрофически — вместо 100мбит у нас 128кбайт в 30мс = 32 мегабита максимум. In Windows Server, the default quantum is a fixed 120ms. При 120мс у нас предельная скорость будет 8.5мбит. То есть на серверной ОС используя буфер в 128кбайт принять 8мбитный поток будет не просто сложно, а архисложно. На десктопных ОС проще, но всё равно проблемы будут при любом чихе. Если буфер больше — становится всё лучше, но всё равно — при любой нестабильности вычитывания начинаются проблемы, которые приводят в простейшем случае к движению рывками, в отдельных случаях к поломке потока или багу аналогичному этому, если переполнится TCP буфер внутри камеры.

Откуда можно сделать только один вывод — буфер так же в идеале должен быть с запасом, примерно в 2 секунды потока, в данном случае — 2 мегабайта. Иначе проблемы вероятны.

Может я и не прав, но если приложение, задача которого принять и сохранить поток от камер, не может этого сделать — это баг. И этот баг надлежит чинить, а не предлагать сводить задачу к уже решенной снижая качество до аналоговой камеры. Dixi.

Источник: habrahabr.ru/post/227483/