Лучший подход к потоковой передаче http в реальном времени на HTML5 video client



Я действительно застрял, пытаясь понять лучший способ потоковой передачи вывода ffmpeg в реальном времени клиенту HTML5 с помощью узла.js, поскольку в игре есть несколько переменных, и у меня нет большого опыта в этом пространстве, проведя много часов, пробуя разные комбинации.



мой вариант использования:



1) поток видеокамеры RTSP H. 264 IP выбран вверх FFMPEG и remuxed в контейнер mp4 используя следующие установки FFMPEG в узле, выходе к STDOUT. Это запускайте только на начальном клиентском соединении, чтобы частичные запросы контента не пытались снова создать FFMPEG.



liveFFMPEG = child_process.spawn("ffmpeg", [
"-i", "rtsp://admin:[email protected]: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);


Я также использовал событие stream для записи данных 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 с 206 HTTP частичным содержимым) клиенту 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 spawn требуется секунда, подключение к IP-камере и отправка фрагментов в узел, а события данных узла также нерегулярны. Однако bytestream должен быть точно таким же, как сохранение в файл, и HTTP должен иметь возможность обслуживать задержки.



4) при проверке сетевого журнала с HTTP-клиента при потоковой передаче файла MP4, созданного FFMPEG с камеры, я вижу, что есть 3 клиентских запроса: общий запрос GET для видео, которое HTTP-сервер возвращает около 40Kb, затем частичный запрос контента с диапазоном байтов для последних 10K файла, затем окончательный запрос для битов в середине не загружается. Может быть, клиент HTML5 после получения первого ответа запрашивает последнюю часть файла для загрузки MP4 Moov atom? Если это так, он не будет работать для потоковой передачи, поскольку нет файла MOOV и нет конца файла.



5) при проверке сетевого журнала при попытке потоковой передачи в прямом эфире, я получаю прерванный первоначальный запрос с получением только около 200 байт, затем повторный запрос снова прерван с 200 байтами и третьим запросом длиной всего 2K. Я не понимаю, почему клиент HTML5 прервал бы запрос, поскольку bytestream точно такой же, как я могу успешно использовать при потоковой передаче из записанного файла. Также кажется, что узел не отправляет остальную часть потока FFMPEG клиенту, но я могу видеть данные FFMPEG в нем .на рутинным событием, поэтому он становится с ffmpeg узла по протоколу HTTP сервер.



6) хотя я думаю, что передача потока STDOUT в буфер ответа HTTP должна работать, мне нужно создать промежуточный буфер и поток, который позволит частичным запросам клиента HTTP работать правильно, как это происходит, когда он (успешно) читает файл? Я думаю, что это основная причина моих проблем, однако я не совсем уверен в узле, как лучше всего настроить это. И я не знаю, как обрабатывать запрос клиента для данных в конце файла, так как нет конец файла.



7) я на неверном пути, пытаясь обработать 206 частичных запросов контента, и должен ли это работать с обычными 200 HTTP-ответами? HTTP 200 ответов отлично работает для VLC, поэтому я подозреваю, что HTML5 video client будет работать только с частичными запросами контента?



поскольку я все еще изучаю этот материал, его трудно работать через различные уровни этой проблемы (FFMPEG, node, streaming, HTTP, HTML5 video), поэтому любые указатели будут высоко оценены. У меня есть провел часы, исследуя этот сайт и сеть, и я не встречал никого, кто мог бы сделать потоковое вещание в режиме реального времени в узле, но я не могу быть первым, и я думаю, что это должно быть в состоянии работать (как-то!).

1366   9  

9 ответов:

EDIT 3: Начиная с IOS 10, HLS будет поддерживать фрагментированные файлы mp4. Ответ теперь, чтобы создать фрагментированные активы mp4, с тире и HLS манифеста. > Притворитесь вспышкой, iOS9 и ниже, а IE 10 и ниже не существует.

все, что ниже этой линии устарел. Держу его здесь для потомков.


EDIT 2: как указывают люди в комментариях, все меняется. Почти все браузеры будут поддерживать кодеки AVC/AAC. iOS по-прежнему требуется ЗОЖ. Но через адаптеры, такие как hls.js вы можете играть ЗОЖ в MSE. Новый ответ-HLS+hls.js, если вам нужна iOS. или просто Фрагментированный MP4 (т. е. тире), если вы не

есть много причин, почему видео и, в частности, видео очень сложно. (Обратите внимание, что в исходном вопросе указано, что видео HTML5 является требованием, но asker заявил, что вспышка возможна в комментариях. Так что сразу же этот вопрос вводит в заблуждение)

сначала я повторите:НЕТ ОФИЦИАЛЬНОЙ ПОДДЕРЖКИ ДЛЯ ПОТОКОВОЙ ПЕРЕДАЧИ В РЕАЛЬНОМ ВРЕМЕНИ ЧЕРЕЗ HTML5. Есть хаки, но ваш пробег может варьироваться.

EDIT: с тех пор, как я написал этот ответ, расширения медиа-источников созрели, и сейчас очень близки к тому, чтобы стать жизнеспособным вариантом. Они поддерживаются в большинстве основных браузеров. IOS продолжает держаться.

Далее, вы должны понимать, что видео по требованию (VOD) и видео очень разные. Да, они оба видео, но проблемы разные, следовательно, форматы разные. Например, если часы на вашем компьютере работают на 1% быстрее, чем следует, вы не заметите на VOD. С живым видео, вы будете пытаться воспроизвести видео, прежде чем это произойдет. Если вы хотите присоединиться к потоку видео в реальном времени, вам нужны данные, необходимые для инициализации декодера, поэтому он должен быть повторен в потоке или отправлен вне полосы. С помощью VOD вы можете прочитать начало файла, который они ищут в любой точке желание.

теперь давайте немного покопаемся.

платформы:

  • iOS
  • PC
  • Mac
  • Android

кодеки:

  • VP8 и аудиокодек/9
  • сек.264
  • Тора (большая перспектива 3)

общие методы доставки для живого видео в браузерах:

  • DASH (HTTP)
  • HLS (HTTP)
  • вспышка (RTMP)
  • вспышка (HDS)

общие способы доставки VOD в браузерах:

  • DASH (http Streaming)
  • HLS (http Streaming)
  • flash (RTMP)
  • flash (http Streaming)
  • MP4 (http псевдо потоковое)
  • я не буду говорить о MKV и OOG, потому что я не знаю их очень хорошо.

html5 Видео тег:

  • MP4
  • webm
  • ogg

давайте посмотрим, какие браузеры поддерживают какие форматы

Safari:

  • HLS (только для iOS и mac)
  • сек.264
  • MP4

Firefox

  • тире (через MSE, но не h. 264)
  • h. 264 через вспышку только!
  • VP9
  • MP4
  • OGG
  • Webm

IE

  • вспышка
  • тире (только через MSE IE 11+)
  • сек.264
  • MP4

Chrome

  • вспышка
  • тире (через MSE)
  • сек.264
  • VP9
  • MP4
  • webm
  • ogg

MP4 не может использоваться для живого видео (Примечание: DASH-это надстройка MP4, поэтому не путайте с этим). MP4 разбивается на две части: moov и mdat. mdat содержит необработанные аудио-видео данные. Но он не индексируется, поэтому без moov он бесполезен. Moov содержит индекс всех данных в mdat. Но из-за его формата он не может быть "сплющен", пока не будут известны временные метки и размер каждого кадра. Возможно, можно построить moov, который "обманывает" размеры кадра, но это очень расточительно пропускная способность мудрая.

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

  • iOS поддерживает только видео h.264. и он поддерживает только HLS для live.
  • Firefox не поддерживает h.264 вообще, если вы не используете flash
  • Flash не работает в iOS

самое близкое к ЖК-дисплею-это использование HLS для получения пользователей iOS, и вспышка для всех остальных. Мой личный фаворит-кодировать HLS, а затем использовать flash для воспроизведения HLS для всех остальных. Вы можете играть в HLS во flash через JW player 6, (или написать свой собственный HLS для FLV в AS3, как я сделал)

скоро, наиболее распространенным способом сделать это будет HLS на iOS/Mac и DASH через MSE везде (это то, что Netflix будет делать в ближайшее время). Но мы все еще ждем, когда все обновят свои браузеры. Вам также, вероятно, понадобится отдельный DASH/VP9 для Firefox (я знаю о open264; это отстой. Он не может делать видео в основном или высоком профиле. Так что в настоящее время бесполезно).

спасибо всем, особенно szatmary, поскольку это сложный вопрос и имеет много слоев, все которые должны работать, прежде чем вы сможете транслировать видео в реальном времени. Чтобы прояснить мой исходный вопрос и HTML5 video use vs flash-мой вариант использования имеет сильное предпочтение HTML5, потому что он является общим, легко реализуемым на клиенте и в будущем. Flash-это далекий второй лучший, поэтому давайте придерживаться HTML5 для этого вопроса.

Я многому научился благодаря этому упражнению и согласен жить потоковая передача намного сложнее, чем VOD (который хорошо работает с видео HTML5). Но я получил это, чтобы работать удовлетворительно для моего случая использования, и решение оказалось очень простым, после того, как выследили более сложные варианты, такие как MSE, flash, сложные схемы буферизации в узле. Проблема заключалась в том, что FFMPEG разрушал фрагментированный MP4, и мне пришлось настраивать параметры FFMPEG, а стандартное перенаправление канала потока узлов через http, которое я использовал изначально, было все, что нужно.

In MP4 существует опция "фрагментация", которая разбивает mp4 на гораздо более мелкие фрагменты, которые имеют свой собственный индекс и делают опцию потоковой передачи mp4 жизнеспособной. Но невозможно вернуться в поток (ОК для моего варианта использования), а более поздние версии FFMPEG поддерживают фрагментацию.

Примечание синхронизация может быть проблемой, и с моим решением у меня есть отставание от 2 до 6 секунд, вызванное комбинацией ремаксов (эффективно FFMPEG должен получить живой поток, remux его затем отправить это к узлу для обслуживания через HTTP). Не так много можно сделать по этому поводу, однако в Chrome видео пытается догнать столько, сколько может, что делает видео немного нервным, но более актуальным, чем IE11 (мой предпочтительный клиент).

вместо того, чтобы объяснять, как код работает в этом сообщении, ознакомьтесь с GIST с комментариями (код клиента не включен, это стандартный тег HTML5 video с адресом http-сервера узла). Суть здесь:https://gist.github.com/deandob/9240090

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

хотя это ответ на мой конкретный вопрос, я выбрал ответ сатмары как принятый, поскольку он является наиболее полным.

один из способов трансляции веб-камеры на основе RTSP на клиент HTML5 (включает в себя повторное кодирование, поэтому ожидайте потери качества и требуется некоторая мощность процессора):

  • настройка сервера icecast (может быть на той же машине, что и веб-сервер, или на машине, которая получает RTSP-поток от cam)
  • на машине, получающей поток от камеры, не используйте FFMPEG, но gstreamer. Он способен принимать и декодировать RTSP-поток, перекодировать его и передавать его в сервера icecast. Пример конвейера (только видео, без звука):

    gst-launch-1.0 rtspsrc location=rtsp://192.168.1.234:554 user-id=admin user-pw=123456 ! rtph264depay ! avdec_h264 ! vp8enc threads=2 deadline=10000 ! webmmux streamable=true ! shout2send password=pass ip=<IP_OF_ICECAST_SERVER> port=12000 mount=cam.webm
    

=> затем вы можете использовать тег

Я написал видеоплеер HTML5 вокруг broadway H264 codec (emscripten), который может воспроизводить живое (без задержки) видео h264 во всех браузерах (desktop, iOS,...).

видеопоток передается через websocket клиенту, декодируется кадр за кадром и отображается в canva (используя webgl для ускорения)

проверить https://github.com/131/h264-live-player на github.

посмотри данное решение. Как я знаю, Flashphoner позволяет воспроизводить живой аудио + видео поток на чистой странице HTML5.

Они использовать MPEG1 и G. 711 кодеки для воспроизведения. Хак отображения декодированного видео на canvas в языке HTML5 и воспроизведении декодируется аудио через HTML5 аудио связи.

Как насчет использования решения jpeg, просто позвольте серверу распространять jpeg один за другим в браузере, а затем использовать элемент canvas для рисования этих jpeg? http://thejackalofjavascript.com/rpi-live-streaming/

Это очень распространенное заблуждение. Нет поддержки видео в реальном времени HTML5 (за исключением HLS на iOS и Mac Safari). Вы можете "взломать" его с помощью контейнера webm, но я бы не ожидал, что это будет поддерживаться повсеместно. То, что вы ищете, включено в расширения источника мультимедиа, где вы можете передавать фрагменты в браузер по одному за раз. но вам нужно будет написать некоторые javascript на стороне клиента.

попробуйте binaryjs. Это так же, как socket.io но единственное, что он делает хорошо, это то, что он транслирует аудио-видео. Binaryjs google it

Comments

    Ничего не найдено.