Проблема сброса и задержки с фрагментированным созданием MP4 в FFMPEG

Я создаю фрагментированный mp4 для потоковой передачи html5, используя следующую команду:

-i rtsp://172.20.28.52:554/h264 -vcodec copy -an -f mp4 -reset_timestamps 1 -movflags empty_moov+default_base_moof+frag_keyframe -loglevel quiet -
  1. "-i rtsp: //172.20.28.52: 554 / h264", поскольку источником является h264 в потоке пакетов rtp с ip-камеры. Для тестирования камера имеет значение GOP 1 (т. Е. Все кадры являются ключевыми).
  2. "-vcodec copy", потому что мне не нужно транскодирование, только повторное смешивание с mp4.
  3. "-movflags empty_moov + default_base_moof + frag_keyframe" для создания фрагментированного mp4 в соответствии со спецификацией расширений источника мультимедиа.
  4. "-" в конце, чтобы вывести mp4 на стандартный вывод. Я беру выходные данные и отправляю их веб-клиенту через веб-сокеты.

Все работает хорошо, ожидайте проблему с задержкой, которую я пытаюсь решить. Если я регистрируюсь каждый раз, когда поступают данные из stdout, с отметкой времени прибытия, я получаю следующие выходные данные:

16/06/2015 15: 40: 45.239 получил размер данных = 24

16/06/2015 15: 40: 45.240 получил размер данных = 7197

16/06/2015 15: 40: 45.241 получил размер данных = 32768

16/06/2015 15: 40: 45.241 получил размер данных = 4941

16/06/2015 15: 40: 45.241 получил размер данных = 12606

16/06/2015 15: 40: 45.241 получил размер данных = 6345

16/06/2015 15: 40: 45.241 получил размер данных = 6339

16/06/2015 15: 40: 45.242 получил размер данных = 6336

16/06/2015 15: 40: 45.242 получил размер данных = 6361

16/06/2015 15: 40: 45.242 получил размер данных = 6337

16/06/2015 15: 40: 45.242 получил размер данных = 6331

16/06/2015 15: 40: 45.242 получил размер данных = 6359

16/06/2015 15: 40: 45.243 получил размер данных = 6346

16/06/2015 15: 40: 45.243 получил размер данных = 6336

16/06/2015 15: 40: 45.243 получил размер данных = 6338

16/06/2015 15: 40: 45.243 получил размер данных = 6357

16/06/2015 15: 40: 45.243 получил размер данных = 6357

16/06/2015 15: 40: 45.243 получил размер данных = 6322

16/06/2015 15: 40: 45.243 получил размер данных = 6359

16/06/2015 15: 40: 45.244 получил размер данных = 6349

16/06/2015 15: 40: 45.244 получил размер данных = 6353

16/06/2015 15: 40: 45.244 получил размер данных = 6382

16/06/2015 15: 40: 45.244 получил размер данных = 6403

16/06/2015 15: 40: 45.304 получил размер данных = 6393

16/06/2015 15: 40: 45.371 получил размер данных = 6372

16/06/2015 15: 40: 45.437 получил размер данных = 6345

16/06/2015 15: 40: 45.504 получил размер данных = 6352

16/06/2015 15: 40: 45,571 получен размер данных = 6340

16/06/2015 15: 40: 45.637 получил размер данных = 6331

16/06/2015 15: 40: 45.704 получил размер данных = 6326

16/06/2015 15: 40: 45.771 получил размер данных = 6360

16/06/2015 15: 40: 45.838 получил размер данных = 6294

16/06/2015 15: 40: 45.904 получил размер данных = 6328

16/06/2015 15: 40: 45.971 получен размер данных = 6326

16/06/2015 15: 40: 46.038 получил размер данных = 6326

16/06/2015 15: 40: 46.105 получил размер данных = 6340

16/06/2015 15: 40: 46.171 получил размер данных = 6341

16/06/2015 15: 40: 46.238 получил размер данных = 6332

Как вы можете видеть, первые 23 строки (которые содержат данные около 1,5 секунд видео) поступают почти мгновенно, а затем задержка между каждыми 2 последовательными строками составляет ~70 мс, что имеет смысл, поскольку видео составляет 15 кадров в секунду. Такое поведение вводит задержку около 1,5 сек.

Это выглядит как проблема сброса, потому что я не вижу причин, по которым ffmpeg должен был бы хранить первые 23 кадра в памяти, тем более что каждый кадр является отдельным фрагментом внутри mp4. Я не мог, однако, найти какой-либо метод, который заставил бы ffmpeg сбрасывать эти данные быстрее.

Кто-нибудь получил предложение?

Я хотел бы отметить, что это следующий вопрос к этому: прямая трансляция тире контента с использованием mp4box

4 ответа

Решение

Ключом к удалению задержки является использование аргумента -probesize:

исследуемое целое число (вход)

Установите размер проб в байтах, то есть размер данных для анализа, чтобы получить информацию о потоке. Более высокое значение позволит обнаружить больше информации в случае ее распространения в потоке, но увеличит задержку. Должно быть целым числом не меньше 32. По умолчанию это 5000000.

По умолчанию значение равно 5 000 000 байт, что эквивалентно ~1,5 с видео. Мне удалось почти полностью устранить задержку, уменьшив значение до 200 000.

Как уже отмечалось, один из способов — перекодировать видео с помощью ffmpeg и выбрать небольшой размер GOP, например. Это работает для меня и дает задержку в несколько сотен мс от IP-камеры до html5.элемент при использовании. Я предполагаю, что когда вы устанавливаете GOP на камере на 1, на самом деле она не дает вам каждый кадр в качестве ключевого кадра, а скорее 1 ключевой кадр в секунду.

Однако в моем случае перекодирование не является вариантом, поэтому ключом к уменьшению задержки до нескольких сотен мс было добавление опции ffmpeg.. Это заставляет ffmpeg создавать очень маленькие фрагменты MP4f и выдавать быстрый и устойчивый поток пакетов на стандартный вывод вместо пакетной обработки их по 1-2 секунды.

Обычно буферизация для stdout отключена в случае вывода на консоль. Если вы запускаете ffmpeg из кода, буферизация включена, поэтому вы получите ваши данные только тогда, когда буфер заполнен или команда завершится.

Вы должны устранить стандартную буферизацию своей ОС. На Windows это невозможно IMO, но на Ubuntu для бывших. Существует http://manpages.ubuntu.com/manpages/maverick/man1/stdbuf.1.html

Я решил проблему с задержкой, используя опцию -g, чтобы установить количество кадров в группе. В моем случае я использовал -g 2, Я подозреваю, что если вы не сделаете это явным, фрагмент либо ждет, пока источник предоставит ключевой кадр, либо использует действительно большое значение по умолчанию для генерации ключевого кадра, прежде чем закрыть фрагмент и вывести его в стандартный вывод.

Другие вопросы по тегам