я сделал код который прнимает несколько потоков и делает из них multi view
в данном случаи показана часть лога для 4 потоков с камер в разных частях здания (потоки можно отличить по цифрам [505])
2022-12-13 02:43:27.986 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:28.768 info [505] --- : Channel 0 is receiving video at 59.149395ffps.
2022-12-13 02:43:31.415 info [457] --- : Channel 0 is receiving video at 33.086918ffps.
2022-12-13 02:43:32.014 info [452] --- : Channel 0 is receiving video at 30.078526ffps.
2022-12-13 02:43:32.120 info [505] --- : Channel 0 is receiving video at 59.667934ffps.
2022-12-13 02:43:32.990 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:33.056 info [466] --- : Receiver connection status changed.
2022-12-13 02:43:35.471 info [505] --- : Channel 0 is receiving video at 59.68681ffps.
2022-12-13 02:43:37.534 info [457] --- : Channel 0 is receiving video at 32.685978ffps.
2022-12-13 02:43:38.187 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:38.249 info [466] --- : Receiver connection status changed.
2022-12-13 02:43:38.714 info [452] --- : Channel 0 is receiving video at 29.849714ffps.
2022-12-13 02:43:38.826 info [505] --- : Channel 0 is receiving video at 59.61486ffps.
2022-12-13 02:43:42.185 info [505] --- : Channel 0 is receiving video at 59.53062ffps.
2022-12-13 02:43:43.186 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:43.458 info [466] --- : Receiver connection status changed.
2022-12-13 02:43:43.694 info [457] --- : Channel 0 is receiving video at 32.466408ffps.
2022-12-13 02:43:45.414 info [452] --- : Channel 0 is receiving video at 29.8547ffps.
2022-12-13 02:43:45.533 info [505] --- : Channel 0 is receiving video at 59.7366ffps.
2022-12-13 02:43:48.386 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:48.454 info [466] --- : Receiver connection status changed.
2022-12-13 02:43:48.940 info [505] --- : Channel 0 is receiving video at 58.70607ffps.
2022-12-13 02:43:49.597 info [457] --- : Channel 0 is receiving video at 33.882202ffps.
2022-12-13 02:43:52.125 info [452] --- : Channel 0 is receiving video at 29.79798ffps.
2022-12-13 02:43:52.239 info [505] --- : Channel 0 is receiving video at 60.625294ffps.
2022-12-13 02:43:53.448 info [466] --- : Receiver connection status changed.
2022-12-13 02:43:53.583 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:55.455 info [457] --- : Channel 0 is receiving video at 34.141876ffps.
2022-12-13 02:43:55.593 info [505] --- : Channel 0 is receiving video at 59.634636ffps.
2022-12-13 02:43:58.454 info [466] --- : Receiver connection status changed.
2022-12-13 02:43:58.786 info [505] --- : Receiver connection status changed.
2022-12-13 02:43:58.813 info [452] --- : Channel 0 is receiving video at 29.904644ffps.
2022-12-13 02:43:58.951 info [505] --- : Channel 0 is receiving video at 59.55274ffps.
из за разной загруженности сети, разного разрешения камер и загруженности CPU fps меняеться
подскажите пожалуйста как можно синхронизировать вывод потоков в multiview
моя начальная идея была запомнить time stamp первого принятого кадра с каждой камеры, использовать его как base time и синхронизировать по ним кадры выводимы на экран
с другой стороны разница небольшая в среднем 0.2 и возможно ее можно проигнорировать
Здравствуйте, sergey2b, Вы писали:
S>из за разной загруженности сети, разного разрешения камер и загруженности CPU fps меняеться S>подскажите пожалуйста как можно синхронизировать вывод потоков в multiview
В общем случае нет никакого FPS. Кадры могут пропадать, FPS меняться и т.д. Это очень ненадёжная характеристика в сети. Опираться нужно на времена семплов и только на них. У каждого канала должен быть таймер (Clock). Принимаешь и декодируешь каждый канал по отдельности и рендеришь кадры по таймеру в multiview back buffer. Back buffer уже по своему таймеру (например 50 Hz) должен выводит все слепленные кадры, независимо ни от чего, на экран.
Или я не понял проблему
Re[2]: как синхронизировать несколько видеостримов
Здравствуйте, Videoman, Вы писали:
V>В общем случае нет никакого FPS. Кадры могут пропадать, FPS меняться и т.д. Это очень ненадёжная характеристика в сети. Опираться нужно на времена семплов и только на них. У каждого канала должен быть таймер (Clock). Принимаешь и декодируешь каждый канал по отдельности и рендеришь кадры по таймеру в multiview back buffer. Back buffer уже по своему таймеру (например 50 Hz) должен выводит все слепленные кадры, независимо ни от чего, на экран. V>Или я не понял проблему
скажите пожалуйста где можно об этом можно почитать, тк
у меня часть потоков 60 fps часть 30 fps
я попробовал у потоков с 60fps использовать только каждый второй кадр в результате движения с этих потков рванные и звук не нормальный
Re[3]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>скажите пожалуйста где можно об этом можно почитать, тк S>у меня часть потоков 60 fps часть 30 fps
Вот где можно почитать я к сожалению не знаю.
S>я попробовал у потоков с 60fps использовать только каждый второй кадр в результате движения с этих потков рванные и звук не нормальный
Давай поэтапно: сделай плеер который проигрывает ровно один сетевой поток, плавно, на экран. Не нужно ни в коем случае ничего выкидывать. Есть таймер, есть время кадра. Как только время >= времени кадра, показываем его. Важно!: считывание, декодирование кадра, его подготовка, должны происходит строго до времени показа. Время показа — только swap кадра на экран. Плавный рендеринг очень сильно зависит от таймингов, так что нужно стараться выдерживать строгую синхронизацию. После того как у тебя получится плеер, который плавно рендерит один стрим, можно переходить к следующей стадии.
Как только будет котов плеер единственного стрима, делаешь несколько плееров, которые работают параллельно, но не на экран, а в back buffer.
Re[4]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>Те первый шаг выполнен
Теперь каждый плеер должен рендерить свои поток в один backbuffer, каждый со своей частотой. Backbuffer должен независимо, рендерить на экран со своей частотой (например 60Hz), независимо. Т.е. multiview, пусть представляет из себя отдельный плеер. Если всё правильно сделать, то рывков никаких не будет. У меня была точно такая же задача, правда на Qt, но в данном контексте это не важно.
Re[6]: как синхронизировать несколько видеостримов
Здравствуйте, Videoman, Вы писали:
V>Теперь каждый плеер должен рендерить свои поток в один backbuffer, каждый со своей частотой. Backbuffer должен независимо, рендерить на экран со своей частотой (например 60Hz), независимо. Т.е. multiview, пусть представляет из себя отдельный плеер. Если всё правильно сделать, то рывков никаких не будет. У меня была точно такая же задача, правда на Qt, но в данном контексте это не важно.
как я понял у меня будет функция которая будет вызываться 60 раз в секунду
считывать очередной фрейм из backbuffer
по его номеру определять в какую позицию экрана его выводить
но если у меня два потока 30 fps и 60fps то в буфере каждую секунду будет 90 фреймов
как мне определить сколько входящих фремов должно участовать в генерации выходящего фрейма 1 или 2
так же возможна ситуация когда в backbuffer будет подряд несколько фреймов из одного входящего потока
Re[4]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>как я понял у меня будет функция которая будет вызываться 60 раз в секунду S>считывать очередной фрейм из backbuffer S>по его номеру определять в какую позицию экрана его выводить
Я запутался и мне казалось, что мы говорим про multiview. Чего-то не договариваешь. Опиши задачу полнее. Я думал что каждый плеер будет рисовать себя в нужную ему область backbuffer-а, а он, в свою очередь, будет рисоваться целиком на весь экран.
S>но если у меня два потока 30 fps и 60fps то в буфере каждую секунду будет 90 фреймов S>как мне определить сколько входящих фремов должно участовать в генерации выходящего фрейма 1 или 2
S>так же возможна ситуация когда в backbuffer будет подряд несколько фреймов из одного входящего потока
Второй вариант, если тебе не нужен единый backbuffer сразу для всех плееров, и не нужно его никуда пересылать, тогда пусть каждый отдельный плеер рисует себя сразу в свой control, widget и т.д.
Здравствуйте, sergey2b, Вы писали:
S>я сделал код который прнимает несколько потоков и делает из них multi view
1) либо сделай все окна мульти-вью незаввисимыми процессами и пусть операционка сама все делает и от тебя не требуется ничего синхрить
2) либо тебе придется научиться интерполировать и экстраполировать изображения потоков
умея это ты просто делаешь общий процесс который выводит в некоторые моменты времени все нужные кадры
и в случае если они еще не поступили или поступили до момента вывода или дропнулись
делается интерполяция или экстраполяция по всем потокам до нужного общего момента вывода.
если дисер пишешь — то тут можно нейронки заюзать и получить зачетный дисер.
Re[2]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>У меня сделан вариант 2 S>И вариант 1 мне не подходит тк конечная цель отпаслась полученный образ multiview по сети
если задача только отсылать то в теории можно 1) захватывать область экрана с потоками... ну это как бы студенчески вариант,
трушныйй — экстраполяция — интерполяция
Re[8]: как синхронизировать несколько видеостримов
на камере стоит настройка 30fps
я сделал тестовое приложение
получаю видофреймы из сети, используя NDI API проверяю стрим 30fps
сохраняю каждый фрейм в очередь
функция вызываемая каждые несколько миллисекунд long interval = trunc((double)1000/fps);
выводит фрейм на экран
бефер видеофреймов быстро переполняеться
я добавил код который считывает frame_rate у видеопотока
// What is the frame rate of this frame.
// For instance NTSC is 30000,1001 = 30000/1001 = 29.97 fps.
int frame_rate_N, frame_rate_D;
и пересчитываю интервал, это не помогло, очередь медленней но переполняеться
если интервал между вызовами сделать короче long interval = trunc((double)1000/fps-4);
очередь сохраняет неусточивое равновесие, но все равно в течении 1-2 часа используюет всю доступную память
как вы считаете, что правильно делать если камера посылает чуть больше кадров чем должно быть
Re[9]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>функция вызываемая каждые несколько миллисекунд long interval = trunc((double)1000/fps);
Вот тут по ходу собака порылась. Нельзя надеяться на то, что функция будет точно вызываться синхронно с частотой потока. У камеры свои часы CamClock и эти часы никогда не будут совпадать с твоими PClock.
Соотношение грубо будет таким: CamClock = PClock * k, где k обычно чуть меньше или чуть больше единицы. Попробуй статистически считать k и подводить свои часы, что бы корректировать ошибку.
По остальному описанию все вроде так, как и должно быть. У меня бывало что часы источника отставали, и у меня начинался голод по кадрам. У каждого сетевого источника свои часы и это логично.
Re[10]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>Скажите пожалуйста где вы про это узнали S>Может есть какие то книги или форумы
эта задача была хорошо изучена в аналогово-цифровых модемах лет 20 назад.
одно из решений — для каждого потока создается свои виртуальные часы идущие снхронно с часами потока
и динамически через цифровую ФАПЧ подстраивающие свою виртуальную скорость хода под скорость потока.
Тогда все буферы примерно постояненны по объему. И в них всегда будут данные.
Глвные часы управлют забором данных из всех буферов и их объединением.
При сильной разнице в скорости потоков — в объединенной картинке будет видно, что где-то изображение идет быстрее а где-то замедленно
но это не мешает объединению в единю картинку.
Здравствуйте, paradok, Вы писали:
P>При сильной разнице в скорости потоков — в объединенной картинке будет видно, что где-то изображение идет быстрее а где-то замедленно P>но это не мешает объединению в единю картинку.
большое спасибо я сейчас погуглю
я использую для комуникации с камерой NDI протокол, в нем в том числе есть функции позволяющие брать фреймы из потока с заданной скоростью
если брать слигком часто функция возращает пустой черный фрейм
как я понимаю эта функция позволяе мне легко реализовать плеер, выбирать фреймы с нужной мне скоростью
правда надо проверить будут ли коректные timestamp у фреймов
// Using a frame-sync we can always get data which is the magic and it will adapt
// to the frame-rate that it is being called with.
NDIlib_video_frame_v2_t video_frame;
NDIlib_framesync_capture_video(pNDI_framesync, &video_frame);
// Display video here. The reason that the frame-sync does not return a frame until it has
// received the frame (e.g. it could return a black 1920x1080 image p) is that you are likely to
// want to default to some video standard (NTSC or PAL) and there would be no way to know what
// your default image should be from an API level.
if (video_frame.p_data) {
// You display the video frame.
}
скажите пожалуйста, а есть ли книги которые стоит почтить по кодекам и обработки видео
Re[11]: как синхронизировать несколько видеостримов
Здравствуйте, sergey2b, Вы писали:
S>Скажите пожалуйста где вы про это узнали
Просто уже 20 лет в мультимедиа как-никак. Частичная подсказка вам есть в DirectShow. У фильтров рендереров и источников есть персональные таймеры — именно по этому. Также, по умолчанию, часы есть у самого графа. До начала работы, граф запрашивает мастер часы, по которым будет работать. Если их нет, то использует свои. У аудио-рендерера всегда есть часы, так как у аудио-платы всегда свой генератор. Если поставите два произвольных компьютера и начнёте играть фильм синхронно, то закончится он играть с разницей несколько секунд на одном и другом. Это именно по тому, что у каждого компьютера часы идут немного по разному.
Какой-нибудь сетевой "Push Demultiplexer" фильтр, тоже всегда имеет часы, именно по этому. Он подсчитывает скорость приходящего потока и подводит часы как на источнике. Граф автоматически использует его часы для рендеринга. Получается что на источнике и приёмнике время часов течёт строго синхронно.
В случае с сетью, источник выдает кадры строго синхронно по своим часам, но относительно ваших часов на приёмнике время будет идти чуть быстрее или чуть медленнее. Ошибка, на самом деле большая, что бы ею можно было пренебречь. Мы как-то считали и получалось уже в 4-м знаке после запятой. Если источник асинхронный (мы можем регулировать его скорость, например файл), то проблемы не возникает, так как мы гарантировано заполняем буфер быстрее хода часов. На синхронном источнике (Live, Сеть) на приёме всегда будет либо перебор, либо недобор.
S>Может есть какие то книги или форумы
Вот к сожалению что-то по книгам подсказать не могу.
Здравствуйте, Videoman, Вы писали:
V>Здравствуйте, sergey2b, Вы писали:
>> синхронном источнике (Live, Сеть) на приёме всегда будет либо перебор, либо недобор.
вроде вот так не будет...
пусть eсть буфера длинной N1..NK
при поступлении очередного кадра из NX потока он добавляется в нужный буфер, а самый кадр старый удаляется из буфера...
а главный объединитель по своим тактам просматривает все буфера и обирает картинку в главный буфер.