Я действительно застрял, пытаясь понять лучший способ потоковой передачи выходных данных ffmpeg в режиме реального времени клиенту HTML5 с помощью node.js, так как есть ряд переменных, и у меня нет большого опыта в этом пространстве, потратив много часов, пробуя разные комбинации.
Мой вариант использования:
1) IP-видеокамера Поток RTSP H.264 принимается FFMPEG и повторно смешивается в контейнере mp4 с использованием следующих настроек FFMPEG в узле, выводится в STDOUT. Это выполняется только при первоначальном клиентском соединении, поэтому частичные запросы контента не пытаются снова порождать FFMPEG.
liveFFMPEG = child_process.spawn("ffmpeg", [
"-i", "rtsp://admin:12345@192.168.1.234:554" , "-vcodec", "copy", "-f",
"mp4", "-reset_timestamps", "1", "-movflags", "frag_keyframe+empty_moov",
"-" // output to stdout
], {detached: false});
2) Я использую http-сервер узла для захвата STDOUT и передачи его обратно клиенту по запросу клиента. Когда клиент впервые подключается, я создаю вышеупомянутую командную строку FFMPEG, а затем передаю поток STDOUT в ответ HTTP.
liveFFMPEG.stdout.pipe(resp);
Я также использовал потоковое событие для записи данных FFMPEG в ответ HTTP, но без разницы
xliveFFMPEG.stdout.on("data",function(data) {
resp.write(data);
}
Я использую следующий HTTP-заголовок (который также используется и работает при потоковой передаче предварительно записанных файлов)
var total = 999999999 // fake a large file
var partialstart = 0
var partialend = total - 1
if (range !== undefined) {
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
}
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total; // fake a large file if no range reques
var chunksize = (end-start)+1;
resp.writeHead(206, {
'Transfer-Encoding': 'chunked'
, 'Content-Type': 'video/mp4'
, 'Content-Length': chunksize // large size to fake a file
, 'Accept-Ranges': 'bytes ' + start + "-" + end + "/" + total
});
3) Клиент должен использовать теги видео HTML5.
У меня нет проблем с потоковым воспроизведением (используя fs.createReadStream с частичным содержимым HTTP 206) для клиента HTML5 видеофайл, ранее записанный с помощью указанной выше командной строки FFMPEG (но сохраненный в файл вместо STDOUT), поэтому я знаю поток FFMPEG правильно, и я даже могу правильно видеть потоковую передачу видео в VLC при подключении к серверу узла HTTP.
Однако попытка потокового вещания из FFMPEG через узел HTTP выглядит намного сложнее, так как клиент отобразит один кадр, а затем остановится. Я подозреваю, что проблема в том, что я не настраиваю соединение HTTP, чтобы быть совместимым с видео клиентом HTML5. Я пробовал разные вещи, такие как использование HTTP 206 (частичное содержимое) и 200 ответов, помещение данных в буфер, а затем потоковую передачу без удачи, поэтому мне нужно вернуться к первым принципам, чтобы убедиться, что я настроил это правильно путь.
Вот мое понимание того, как это должно работать, поправьте меня, если я ошибаюсь:
1) FFMPEG должен быть настроен для фрагментации вывода и использования пустого moov (флаги FFMPEG frag_keyframe и empty_moov mov). Это означает, что клиент не использует атом moov, который обычно находится в конце файла, который не имеет отношения к потоковой передаче (без конца файла), но означает, что поиск невозможен, что хорошо для моего варианта использования.
2) Несмотря на то, что я использую фрагменты MP4 и пустой MOOV, мне все равно нужно использовать частичное содержимое HTTP, так как проигрыватель HTML5 будет ждать, пока весь поток не загрузится, прежде чем играть, что с живым потоком никогда не заканчивается, поэтому не работает.
3) Я не понимаю, почему передача потока STDOUT в ответ HTTP не работает при потоковой передаче в реальном времени. Если я сохраню в файл, я могу легко передать этот файл клиентам HTML5, используя подобный код. Может быть, это проблема синхронизации, так как для запуска порождения FFMPEG требуется секунда, он подключается к IP-камере и отправляет порции на узел, а события данных узла также нерегулярны. Однако поток данных должен быть точно таким же, как при сохранении в файл, и HTTP должен быть способен справляться с задержками.
4) При проверке сетевого журнала от HTTP-клиента при потоковой передаче файла MP4, созданного FFMPEG с камеры, я вижу, что есть 3 клиентских запроса: общий запрос GET для видео, который HTTP-сервер возвращает около 40 КБ, затем частичный запрос контента с байтовым диапазоном для последних 10КБ файла, затем окончательный запрос для битов в середине не загружен. Может быть, клиент HTML5, получив первый ответ, запрашивает последнюю часть файла для загрузки атома MP4 MOOV? В этом случае он не будет работать для потоковой передачи, так как нет файла MOOV и нет конца файла.
5) При проверке сетевого журнала при попытке потокового вещания я получаю прерванный начальный запрос только с полученными приблизительно 200 байтами, затем повторный запрос снова прерывается с 200 байтами и третьим запросом, длина которого составляет всего 2 КБ. Я не понимаю, почему клиент HTML5 прервал запрос, поскольку поток байтов точно такой же, какой я могу успешно использовать при потоковой передаче из записанного файла. Также кажется, что узел не отправляет оставшуюся часть потока FFMPEG клиенту, но я вижу данные FFMPEG в подпрограмме события .on, поэтому он попадает на HTTP-сервер узла FFMPEG.
6) Хотя я думаю, что передача потока STDOUT в буфер ответов HTTP должна работать, мне нужно создать промежуточный буфер и поток, которые позволят клиентским запросам частичного содержимого HTTP работать должным образом, как это происходит, когда он (успешно) читает файл ? Я думаю, что это главная причина моих проблем, но я не совсем уверен, как лучше всего это настроить. И я не знаю, как обработать клиентский запрос данных в конце файла, поскольку у него нет конца файла.
7) Я ошибаюсь, пытаясь обработать 206 частичных запросов контента, и должно ли это работать с обычными 200 HTTP-ответами? HTTP 200 ответы отлично работают для VLC, поэтому я подозреваю, что видео-клиент HTML5 будет работать только с частичными запросами контента?
Так как я все еще изучаю этот материал, трудно разобраться с различными уровнями этой проблемы (FFMPEG, узел, потоковая передача, HTTP, видео HTML5), поэтому любые указатели будут высоко оценены. Я провел часы, исследуя этот сайт и сеть, и я не встречал никого, кто мог бы выполнять потоковую передачу в реальном времени на узле, но я не могу быть первым, и я думаю, что это должно сработать (каким-то образом !).
Content-Type
в голову? Вы используете чанк код? Вот где я бы начал. Кроме того, HTML5 не обязательно обеспечивает функциональность для потоковой передачи, вы можете прочитать об этом здесь . Скорее всего, вам потребуется реализовать способ буферизации и воспроизведения видеопотока своими собственными средствами ( см. Здесь ), хотя это, вероятно, не очень хорошо поддерживается. Также загляните в MediaSource API.Ответы:
Все под этой строкой устарело. Держу это здесь для потомков.
Есть много причин, почему видео и, в частности, живое видео очень сложно. (Обратите внимание, что в первоначальном вопросе указывалось, что HTML5-видео является обязательным требованием, но спрашивающий заявил, что Flash возможен в комментариях. Поэтому сразу же этот вопрос вводит в заблуждение)
Сначала я повторю: ОФИЦИАЛЬНОЙ ПОДДЕРЖКИ ДЛЯ ПРЯМОГО ПОТОКА НЕ НУЖНО . Есть взломы, но ваш пробег может отличаться.
Далее, вы должны понимать, что видео по запросу (VOD) и живое видео очень разные. Да, они оба видео, но проблемы разные, поэтому форматы разные. Например, если часы на вашем компьютере работают на 1% быстрее, чем должны, вы не заметите на VOD. С живым видео вы будете пытаться воспроизвести видео до того, как это произойдет. Если вы хотите присоединиться к текущему потоковому видео, вам нужны данные, необходимые для инициализации декодера, поэтому они должны быть повторены в потоке или отправлены вне полосы. С VOD вы можете прочитать начало файла, к которому они стремятся, в любую точку, которую вы хотите.
Теперь давайте немного покопаемся.
Платформы:
Кодеки:
Распространенные способы доставки живого видео в браузерах:
Общие методы доставки для VOD в браузерах:
HTML5 тег видео:
Давайте посмотрим, какие браузеры поддерживают какие форматы
Сафари:
Fire Fox
IE
Хром
MP4 нельзя использовать для живого видео (ПРИМЕЧАНИЕ: DASH - это расширенный набор MP4, поэтому не путайтесь с этим). MP4 разбит на две части: moov и mdat. mdat содержит необработанные аудио-видео данные. Но это не индексируется, поэтому без moov это бесполезно. Moov содержит индекс всех данных в mdat. Но из-за своего формата его нельзя «сплющить», пока не будут известны временные метки и размер КАЖДОГО кадра. Может быть возможно построить moov, который «подставляет» размеры кадра, но это очень расточительно с точки зрения пропускной способности.
Поэтому, если вы хотите доставить везде, нам нужно найти наименьший общий знаменатель. Вы увидите, что здесь нет LCD, не прибегая к примеру со вспышкой:
Самое близкое к ЖК-дисплею - использование HLS для привлечения пользователей iOS и прошивка для всех остальных. Мой личный фаворит - это кодирование HLS, а затем использование Flash для воспроизведения HLS для всех остальных. Вы можете воспроизводить HLS во флэш-памяти через JW player 6 (или написать свой собственный HLS для FLV в AS3, как я)
Вскоре наиболее распространенным способом сделать это будет HLS на iOS / Mac и DASH через MSE везде (это то, что Netflix будет делать в ближайшее время). Но мы все еще ждем, чтобы все обновили свои браузеры. Вам также, вероятно, понадобится отдельный DASH / VP9 для Firefox (я знаю об open264; он отстой. Он не может делать видео в основном или высоком профиле. Поэтому в настоящее время он бесполезен).
источник
Спасибо всем, особенно szatmary, так как это сложный вопрос, имеющий много слоев, и все это должно работать, прежде чем вы сможете транслировать живое видео. Чтобы прояснить мой исходный вопрос и использование HTML5-видео вместо флэш-памяти, мой вариант использования имеет сильные предпочтения для HTML5, потому что он универсальный, его легко реализовать на клиенте и в будущем. Flash занимает второе место, поэтому давайте придерживаться HTML5 для этого вопроса.
Я многому научился благодаря этому упражнению и согласен, что потоковое вещание намного сложнее, чем VOD (который хорошо работает с видео HTML5). Но я сделал так, чтобы это работало удовлетворительно для моего варианта использования, и решение оказалось очень простым, после того, как мы выбрали более сложные опции, такие как MSE, flash, сложные схемы буферизации в Node. Проблема заключалась в том, что FFMPEG искажал фрагментированный MP4, и мне пришлось настраивать параметры FFMPEG, а перенаправление канала потока стандартного узла через http, которое я использовал изначально, было всем, что было нужно.
В MP4 есть опция 'фрагментации', которая разбивает mp4 на гораздо меньшие фрагменты, которые имеют свой собственный индекс, и делает опцию прямой трансляции mp4 жизнеспособной. Но невозможно вернуться обратно в поток (хорошо для моего варианта использования), и более поздние версии FFMPEG поддерживают фрагментацию.
Время синхронизации заметок может быть проблемой, и с моим решением у меня задержка составляет от 2 до 6 секунд, вызванная сочетанием ремикса (фактически FFMPEG должен получать живой поток, ремуксировать его, а затем отправлять его на узел для обслуживания по HTTP) , С этим ничего не поделаешь, однако в Chrome видео пытается наверстать упущенное, что делает его немного нервным, но более актуальным, чем IE11 (мой предпочтительный клиент).
Вместо того, чтобы объяснять, как работает код в этом посте, ознакомьтесь с GIST с комментариями (код клиента не включен, это стандартный HTML-тег HTML5 с адресом http-узла). GIST находится здесь: https://gist.github.com/deandob/9240090
Мне не удалось найти похожие примеры этого варианта использования, поэтому я надеюсь, что приведенное выше объяснение и код помогут другим, особенно потому, что я многому научился на этом сайте и все еще считаю себя новичком!
Хотя это ответ на мой конкретный вопрос, я выбрал ответ szatmary в качестве принятого, поскольку он является наиболее полным.
источник
Взгляните на проект JSMPEG . Там реализована отличная идея - декодировать MPEG в браузере с помощью JavaScript. Байты из кодировщика (например, FFMPEG) могут быть переданы в браузер, например, с помощью WebSockets или Flash. Если сообщество наверстает упущенное, я думаю, что это пока будет лучшим решением для потокового видео в формате HTML5.
источник
Я написал видеоплеер HTML5 на базе кодека Broadway H264 (emscripten), который может воспроизводить видео H264 в реальном времени (без задержки) во всех браузерах (настольный компьютер, iOS, ...).
Видеопоток отправляется через websocket клиенту, декодированный кадр за кадром и отображается в канве (используя webgl для ускорения)
Проверьте https://github.com/131/h264-live-player на github.
источник
Один из способов прямой трансляции веб-камеры на основе RTSP на клиент HTML5 (включает перекодирование, поэтому ожидайте потери качества и требуйте некоторой мощности ЦП):
На машине, принимающей поток с камеры, не используйте FFMPEG, а gstreamer. Он может принимать и декодировать RTSP-поток, перекодировать его и передавать на сервер icecast. Пример конвейера (только видео, без звука):
=> Затем можно использовать тег <video> с URL-адресом icecast-stream ( http://127.0.0.1:12000/cam.webm ), и он будет работать во всех браузерах и устройствах, поддерживающих webm
источник
Посмотрите на это решение . Как я знаю, Flashphoner позволяет воспроизводить потоковое аудио + видео на чистой странице HTML5.
Для воспроизведения используются кодеки MPEG1 и G.711 . Хак рендерит декодированное видео в элемент HTML5 canvas и проигрывает декодированное аудио через аудио-контекст HTML5.
источник
Как насчет использования решения jpeg, просто разрешите серверу распространять jpeg один за другим в браузер, а затем используйте элемент canvas для рисования этих jpegs? http://thejackalofjavascript.com/rpi-live-streaming/
источник
Это очень распространенное заблуждение. Нет прямой поддержки видео HTML5 (за исключением HLS на iOS и Mac Safari). Возможно, вы сможете «взломать» его, используя контейнер webm, но я не ожидаю, что это будет поддерживаться повсеместно. То, что вы ищете, включено в Расширения Media Source, где вы можете передавать фрагменты в браузер по одному. но вам нужно будет написать некоторый клиентский JavaScript.
источник
solutions
но неsupport
для прямой трансляции. Это прямо ссылается на мой комментарий, увиденный выше. И webm поддерживается в основных браузерах, в основном это последняя стабильная версия.Попробуйте бинарный файл. Это так же, как socket.io, но единственное, что он делает хорошо - это потоковое аудио-видео. Binaryjs Google это
источник