Проблема сброса и задержки с фрагментированным созданием 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 -
- "-i rtsp: //172.20.28.52: 554 / h264", поскольку источником является h264 в потоке пакетов rtp с ip-камеры. Для тестирования камера имеет значение GOP 1 (т. Е. Все кадры являются ключевыми).
- "-vcodec copy", потому что мне не нужно транскодирование, только повторное смешивание с mp4.
- "-movflags empty_moov + default_base_moof + frag_keyframe" для создания фрагментированного mp4 в соответствии со спецификацией расширений источника мультимедиа.
- "-" в конце, чтобы вывести 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, например
Однако в моем случае перекодирование не является вариантом, поэтому ключом к уменьшению задержки до нескольких сотен мс было добавление опции ffmpeg.
Обычно буферизация для stdout отключена в случае вывода на консоль. Если вы запускаете ffmpeg из кода, буферизация включена, поэтому вы получите ваши данные только тогда, когда буфер заполнен или команда завершится.
Вы должны устранить стандартную буферизацию своей ОС. На Windows это невозможно IMO, но на Ubuntu для бывших. Существует http://manpages.ubuntu.com/manpages/maverick/man1/stdbuf.1.html
Я решил проблему с задержкой, используя опцию -g, чтобы установить количество кадров в группе. В моем случае я использовал -g 2
, Я подозреваю, что если вы не сделаете это явным, фрагмент либо ждет, пока источник предоставит ключевой кадр, либо использует действительно большое значение по умолчанию для генерации ключевого кадра, прежде чем закрыть фрагмент и вывести его в стандартный вывод.