Привет. Есть устройство, вещающее по сети видео-аудио стрим. С этим устройством есть проблема: внутреннее время устройства идет чуть-чуть быстрее, чем реальное время. Из-за этого timestamps кадров растет чуть-чуть быстрее. Из-за этого, при проигрывании кадров с синхронизацией по компьютерным часам, происходящее на экране потихоньку отстает от реально происходящего. За сутки набегает примерно 7-8 секунд. Я попробовал сделать следующее: запустил стрим на 2-3 дня, и мерял разницу общего времени стрима, и общего времени по компьютерным часам. После этого разделил одно на другое, и получил некий коэффициент, на который в новой версии плеера умножат timestamps. Ситуация улучшилась, но не слишком хорошо - похоже, что на разных устройствах этот коэффициент разный, в связи с чем, новые стримы либо все так же отстают (только медленнее), либо наоборот, уходят "в прошлое". В связи с этим мне интересно, возможно ли вычислять этот коэффициент на лету? Нужно не просто постоянно делить одно на другое, но и соблюсти два условия: 1. Любая пара ближайших timestamps T(n) и T(n+1) после калибровки должна сохранить условие T(n) <= T(n+1). 2. Калибрация аудио-фреймов меняющимся параметром не должна давать артефактов, заметных на слух. Прошу советов мудрых.
_DEN_ 3-7 секунд в сутки стандартная погрешность кварцевого генератора. При этом еще она меняет от перепада температуры. Примерно на столько же. Ну так делай замер не 2-3 суток, а по 5-30 минут. 24ч/30мин=48 7/48=0,14583 на при частоте 30 кадров на 4 убегут. Значит надо делать замер 5 минут и затем корректировать ваш timestamps
Как я понимаю, у тя синхронизация по звуку и видео не совпадает. Я бы сначала поковырял спецификации формата стрима. По любому там должен быть какой нить синхронизирующий счетчик. А измерять каким то опытным путем - последний вариант.
jabocrack У человека свой сервак и свой формат. Проблема в рассинхронизации времени на сервере и клиенте. Обычно жёсткая синхронизация не требуется(к примеру в потоковом радио). Но если она нужна, то можно тупо скажем раз в час, начинать на клиенте отсчёт с нуля(то есть брать время прихода кадра за текущее) и всё.
Booster "Свой сервак" - это выражение к теме не относится, выбрасываем. Остается "У человека свой формат". Ого. Не поверю.
jabocrack У меня простейший HTTP Multipart формат. Заголовок - данные - заголовок - данные. Timestamp берется из заголовка. Никаких допольнительных данных для синхронизации нет. Совпадает. Просто без корректирования происходящее на мониторе начинает отставать от ИРЛ. Pavia У меня вот тоже примерно такая мысль... Надо будет попробовать. Главное чтобы не было заметных артефактов. Booster Ай умный какой. Мне надо чтобы стрим непрерывно работал неделями, без каких-либо пересоединений.
_DEN_ Если у Вас сторонние плеера, то ничем помочь не могу. Костыли предлагать не буду. В общем надо описывать проблему более детально, чтобы небыло недопониманий, мы не телепаты.
Booster Да не, плеер-то свой. Что хочу в нем, то и пишу. А проблема проста и описывать тут особо нечего. Секунда на часах энкодера, которые штампуют кадры, чуть-чуть короче, чем настоящая секунда.
_DEN_ Тогда не вижу проблемы. Ведь когда приходит первый фрейм, он ведь проигрывается сразу(ну или с небольшой задержкой буферизации) на клиенте независимо от того какое время стоит во фрейме, а далее проигрывание идёт относительно времени клиента. Невижу препятствий делать тоже самое, с некоторой периодичностью. Переконнект для этого абсолютно не нужен.
Объясняю. Когда приходит первый кадр, то заводится два относительных счетчика времени (относительно первого кадра). Счетчик реального времени и счетчик времени потока. Каждый следующий кадр вынимается из буфера и отправляется на рендеринг (на проигрывание) по условию что время этого кадра в его относительно-потоковых часах меньше (или равно), чем относительное реальное время. Код (Text): CPU time: 1 Next frame time: 2 Действите: ничего не делаем CPU time: 2 Next frame time: 2 Действите: вынимаем кадр и кидаем на рендер CPU time: 3 Next frame time: 7 Действите: ничего не делаем CPU time: 4 Next frame time: 7 Действите: ничего не делаем ... Проигрывание идет относительно времени клиента, это да. Но нужно понимать, что стоит за этой фразой. А за этой фразой стоит периодическое сравнение времени клиента и штампа кадра. И штамп кадра - неправильный (линейно сжат-растянут на неизвестный коэффициент). И это и есть проблема.
Вот как я себе понимаю этот процесс. Клиент подключился, пришёл первый по счёту кадр, в этом кадре стоит какой-то штамп времени сервера. Но время сервера и клиента наверняка не синхронны, по-этому мы принимаем время первого кадра за время которое сейчас на клиенте. Далее синхронизируемя по разнице времени между текущим штампом кадра и штампом самого первого кадра. Но конечно время на сервере и клиенте идёт с разной скоростью и по-этому накапливается ошибка, по-этому мы периодически принимаем текущий кадр за первый и уже считаем время относительно него, то есть как буд-то переконнектились, но на самом деле просто синхронизировались.
Это даст накопительную ошибку. Приняв текущий кадр за первый, мы внесем ошибку, равную разнице на момент принятия. В итоге ничего не изменится.
_DEN_ Какую ошибку? Всё будет нормально. Если фреймы приходят с некоторой задержкой, то тут всё равно ничего не поделаешь. А чтобы убрать ошибку разной скорости времени на сервере и клиенте, я и предлагаю периодически снова брать текущий фрейм за нулевой.
Для простоты представь, что время на камере бежит в 2 раза быстрее. Мы посмотрели 1 час в реальном времени. У нас будет показано пол часа видео, и пол часа будет в буффере. Ну примим мы текущий кадр за первый, ну и что? У нас уже есть пол часа ошибки, и они никуда не денутся. А выкидывать буффер нельзя.
_DEN_ Зато факт прихода кадра и есть настоящая точка отсчёта ) Он же не будет у тебя 7-8 секунд блуждать по сети Поэтому просто раз в 10 мин. копируй счётчик из штампа в счётчик времени клиента и продолжай их увеличивать как и до этого. Микроартефакт при этом будет, но он будет не отличим от потери одиночного кадра которая и без этого может произойти. ЗЫ: это я совет Booster пытаюсь переформулировать чтобы дошло
Прошло 1000 реальных секунд, и 1010 секунд по мнению стрима. Приняв текущий кадр за первый, мы получим ошибку в 10 секунд, т.к. синхронизируясь по часам компа, мы покажем не 1000 секунд видео, а 1000 * (1000 / 1010) = ~990 секунд видео.