Допустим я знаю точное физ. время первого кадра mp4 файла (I-frame который).
Могу ли я с помощью соотв. кода (отсюда):
def with_cv2(video: str) -> List[int]:
"""
Link: https://pypi.org/project/opencv-python/
My comments:
I don't know why, but the last 4 or 5 timestamps are equal to 0 when they should not.
Also, cv2 is slow. It took my computer 132 seconds to process the video.
Parameters:
video (str): Video path
Returns:
List of timestamps in ms
"""
timestamps = []
cap = cv2.VideoCapture(video)
while cap.isOpened():
frame_exists, curr_frame = cap.read()
if frame_exists:
timestamps.append(t0+ round(cap.get(cv2.CAP_PROP_POS_MSEC)))#добавил t0 для наглядности.else:
break
cap.release()
return timestamps
получить точное физ. время (capture time) фрейма? Ну т.е. в коде выше я просто плюсую cap.get(cv2.CAP_PROP_POS_MSEC))
к известному физ. времени для первого кадра ( t0+ cap.get(cv2.CAP_PROP_POS_MSEC)) ). Или это не то?
Это как бы время расстояния между кадрами (CAP_PROP_POS_MSEC), верно? Но оно не говорит, как кадры получались
на камере или говорит? С одной стороны fps постоянный, так что вроде кадры получаются через одинаковые промежутки
времени, так что вроде зная время базового фрейма можно выч. физ. время последующих фреймов.
Вроде все бьется, но не могут ли быть какие-нибудь еще задержки, которые могли бы исказить реальное время фреймов?
Может быть, что сеть потеряла некоторые фреймы, что тогда? Будет ли код выше по-прежнему верным?
Не очень хороший вариант: с вероятностью 95% через какое-то время начнется рассинхра между посчитанным временем и реальным. Опять же, все зависит от требуемой точности. Если нужны примерные часы "на глаз", камера имеет стабильное подключение, ничего не фризит, и капчурить в течение 15-ти минут, условно — то может и ок будет. Но по-хорошему надо, конечно, делать иначе.
PS ты б описал всю задачу: с какой камеры куда передаешь; что хочешь получить; какие компоненты (GStreamer/FFmpeg/OpenCV) используешь и так далее. По постам видно, что вокруг этой темы ходишь уже некоторое время, но, видимо, с разными решениями так и не получается.
Патриот здравого смысла
Re: [OpenCv]Получить физ. время фрейма, зная точное время I-frame'а?
Здравствуйте, Sharov, Вы писали:
S>Вроде все бьется, но не могут ли быть какие-нибудь еще задержки, которые могли бы исказить реальное время фреймов?
Вроде бы — да. Точность не гарантирована. Дело в том, что OpenCV для захвата может использовать разные бэкенды, каждый из которых (для h.264 например) возвращает время и продолжительность кадра, начиная с начала видео. Но, как написали ниже, это не точно. Для OpenCV + gstreamer вообще проблема известна.
S>Может быть, что сеть потеряла некоторые фреймы, что тогда? Будет ли код выше по-прежнему верным?
Не будет. К сожалению, даже не все камеры присылают pts/dts.
Re[2]: [OpenCv]Получить физ. время фрейма, зная точное время I-frame'а?
Здравствуйте, DiPaolo, Вы писали:
DP>Не очень хороший вариант: с вероятностью 95% через какое-то время начнется рассинхра между посчитанным временем и реальным. Опять же, все зависит от требуемой точности. Если нужны примерные часы "на глаз", камера имеет стабильное подключение, ничего не фризит, и капчурить в течение 15-ти минут, условно — то может и ок будет. Но по-хорошему надо, конечно, делать иначе.
Как иначе?
DP>PS ты б описал всю задачу: с какой камеры куда передаешь; что хочешь получить; какие компоненты (GStreamer/FFmpeg/OpenCV) используешь и так далее. По постам видно, что вокруг этой темы ходишь уже некоторое время, но, видимо, с разными решениями так и не получается.
С помощью gstreamer'а нарезать rtsp поток на файлы mp4, причем необходимо для фреймов хранить capture time.
gstreamer вроде бы умеет добавлять метаданные для фрейма.
Пока для PoC я как-то обновляю метку времени и беру ее последнее значение в качестве имени файла (чтобы проще было считать все остальное),
но в идеале для каждого фрейма надо бы хранить capture time, и как это сделать --
Т.е. считаю, что текущее значение ts есть физ. время первого(ключевого) фрейма камеры.
Пока есть это:
foreach (Pad pad in splitmuxsink.Pads)
{
if (pad.Direction == PadDirection.Sink)
{
pad.AddProbe(PadProbeType.Buffer, (pad, probeInfo) =>
{
var buf = probeInfo.Buffer;
var metaTs = buf.GetReferenceTimestampMeta();
if (metaTs.Timestamp > 0)
{
gstTs= metaTs.Timestamp;
// System.Diagnostics.Debug.WriteLine($"probe counter: {probeCounter}");
Interlocked.Increment(ref probeCounter);
}
//System.Diagnostics.Debug.WriteLine($"splitmuxsink element, buffer ts: {metaTs.Timestamp}");return PadProbeReturn.Ok;
});
}
}
var formatLocation = new Action<object, object>((o, args) =>
{
System.Diagnostics.Debug.WriteLine($"new file counter: {newFileCounter}, probes since last file:{probeCounter}");
splitmuxsink["location"] = $"some_path\\{gstTs}.mp4";
Interlocked.Increment(ref newFileCounter);
probeCounter = 0;
});
Тут засада в том, GetReferenceTimestampMeta() вроде что-то возвращает, но может возвращать одно и тоже или вообще ничего, поскольку
зависит от RTCP пакета, которые бывает раз в 5 секунд или что-то вроде того. Тут больше деталей.
Т.е. как вообще делать например, коллаж видео с разных камер, чтобы расхождение между соотв. фреймами были минимальны? Т.е. понятно,
что есть какой-то дрейф на стороне камеры, но как-то все это уменьшить и сделать максимально синхронным. Т.е. надо как-то хранить или
уметь получать физ. время фреймов. Вроде, по идее, стандартная задача.
Кодом людям нужно помогать!
Re[2]: [OpenCv]Получить физ. время фрейма, зная точное время
S>>Вроде все бьется, но не могут ли быть какие-нибудь еще задержки, которые могли бы исказить реальное время фреймов? N>Вроде бы — да. Точность не гарантирована. Дело в том, что OpenCV для захвата может использовать разные бэкенды, каждый из которых (для h.264 например) возвращает время и продолжительность кадра, начиная с начала видео. Но, как написали ниже, это не точно. Для OpenCV + gstreamer вообще проблема известна.
S>>Может быть, что сеть потеряла некоторые фреймы, что тогда? Будет ли код выше по-прежнему верным? N>Не будет. К сожалению, даже не все камеры присылают pts/dts.
Правильно ли я понимаю проблему -- пусть у нас получаются фреймы на камере f1,f2,f3,f4,...,f10.
Я их принимаю, но теряю, скажем f3, f1,f2,f4,....,f10. Тогда у меня вроде как получается видео,
но без f3 и когда я начинаю считать время, у меня все съежает на f4, т.к. мы полагаем что он получился
сразу после f2, т.е. через 1000/fps, а в реальности 2000/fps (ну или как-то так). И вот тут нерешаемы проблемы,
которые только через метаданные для каждого фрейма -- https://gstreamer.freedesktop.org/documentation/application-development/advanced/metadata.html
Например, да. Я уже много лет работаю с кастомными камерами, которые присылают всё что нужно и даже больше. Ну и с gstreamer знаком шапочно, потому не могу сказать прямо все детали. Но по старому опыту — да, всё верно. Поэтому до сих пор актуален проект с кастомизированным ffmpeg для синхронизации разных видео.
Re[3]: [OpenCv]Получить физ. время фрейма, зная точное время I-frame'а?
Смотреть на метки времени фреймов (PTS/DTS).
S>Т.е. как вообще делать например, коллаж видео с разных камер, чтобы расхождение между соотв. фреймами были минимальны? Т.е. понятно, S>что есть какой-то дрейф на стороне камеры, но как-то все это уменьшить и сделать максимально синхронным. Т.е. надо как-то хранить или S>уметь получать физ. время фреймов. Вроде, по идее, стандартная задача.
Я с гстримером мало знаком. Может найду время накатать пример в течение недели. В целом, тут два варианта:
— писать свой элемент и в нем обрабатывать GstBuffer-а, беря из них метки времени. Но, не факт, что твой сорцовый элемент будет их отдавать (надо уточнять)
— писать на коллбэках для собранного пайплайна, типа как в примере https://gstreamer.freedesktop.org/documentation/tutorials/basic/time-management.html?gi-language=c
Патриот здравого смысла
Re[3]: [OpenCv]Получить физ. время фрейма, зная точное время
S>Правильно ли я понимаю проблему -- пусть у нас получаются фреймы на камере f1,f2,f3,f4,...,f10. S>Я их принимаю, но теряю, скажем f3, f1,f2,f4,....,f10. Тогда у меня вроде как получается видео, S>но без f3 и когда я начинаю считать время, у меня все съежает на f4, т.к. мы полагаем что он получился S>сразу после f2, т.е. через 1000/fps, а в реальности 2000/fps (ну или как-то так). И вот тут нерешаемы проблемы, S>которые только через метаданные для каждого фрейма -- https://gstreamer.freedesktop.org/documentation/application-development/advanced/metadata.html
Тут конечно можно считать дропнутые/потерянные фреймы (в RTSP есть спец. поток для статистики — RTCP, там и номера пакетов есть). Однако, никто не застрахован от фризов на камере (например, был фрейм #N, потом фризы на камере или перегрузка ее и 2 сек не было стрима, потом идет фрейм #N + 1, а по сути 2 секунды уже прошло). Ну по-любомы инкрементное вычисление несет много потенциальных проблем.