Кто-то спросил меня, как вести видеопоток с помощью Node.js. Это то, чего я еще не пробовал, поэтому я подумал: Почему бы и нет! Позвольте мне поделиться с вами своими выводами.

Задача заключалась в создании маршрута, который отправляет файл .mp4 на страницу и делает видео доступным для просмотра.

Как я это разложил:

  • Сделайте серверный маршрут для подачи видео.
  • Используйте HTML5 и JS для запроса фида.
  • Сделайте загрузку видео по частям, а не с самого начала.

TL; DR - Вы можете найти рабочую демонстрацию потокового видео здесь.

Потоки

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

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

Вы также можете использовать этот подход для отправки больших фрагментов текста. Например, вашему клиенту не придется так долго ждать, пока появятся первые несколько строк статьи.

Немного теории

  • Получение размера файла: fs в Node имеет метод statSync, который возвращает статистику файла. Среди этой статистики - размер файла, который нам нужно знать, когда загруженный в данный момент фрагмент достиг конца файла. Вы также можете использовать stat - в моем случае я попытался избежать синхронности, чтобы код был более понятным для новичков.
  • Создание потока из файла: fs содержит другой метод с именем createReadStream, который будет создавать поток с учетом файла, начального и конечного фрагментов.
const fileChunk = fs.createReadStream(sample.mp4, {start, end});
  • Размер блоков: начальный блок будет доступен вам в запросе. Чтобы выяснить, какую часть файла нужно загрузить, я использую это вычитание из размера конечного фрагмента (если он недоступен, используйте полный размер файла) и размера начального фрагмента:
                          endChunk - startChunk
  • HTTP 206: используется для частичного содержимого, которым мы хотим, чтобы заголовок нашего соединения был. Мы непрерывно загружаем фронтенд кусками, и мы хотим, чтобы наш начальный кусок был доступен, когда делается запрос. Вы должны хотя бы определить:
'Content-Range': 'bytes chunkStart-chunkEnd/chunkSize'
'Accept-Ranges': 'bytes'
'Content-Length': chunkSize
'Content-Type': 'video/mp4'

Сервер

Принимая во внимание эти вещи, я получил что-то вроде этого в моем маршруте с именем video. (Я использую Express для создания маршрута.)

Это довольно много кода. Не волнуйтесь, вы всегда можете отладить его с помощью демо.

Позвольте мне попытаться объяснить поток:

  • Когда делается запрос, мы получаем размер файла и отправляем первые несколько фрагментов видео в операторе else.
  • Когда мы начинаем смотреть видео (получая доступ к маршруту через localhost:3000/video или из внешнего интерфейса), выполняются последующие запросы, на этот раз с диапазоном в заголовке, чтобы мы знали начальную точку нашего следующего фрагмента.
  • Прочтите файл еще раз, чтобы создать другой поток, передав новое значение для начала и конца (которое, скорее всего, будет текущей частью, указанной в заголовке запроса, и размером файла видео).
  • Мы устанавливаем наш ответ заголовка 206 для отправки только части нашего вновь созданного потока, применяя формулу, о которой мы говорили ранее.

Внешний интерфейс

Интерфейс на удивление прост с тегом HTML5 video - вам просто нужно добавить исходный маршрут, и он сделает все остальное за вас.

<video id="videoPlayer" controls>
  <source src="http://localhost:3000/video" type="video/mp4">
</video>

Атрибут controls позволяет видеть элементы управления плеером.

Без него вы можете вместо этого запрограммировать эти и другие свойства самостоятельно, обратившись к элементу player; в данном случае идентификатор videoPlayer.

Итак, если у вас есть кнопка в вашем HTML, вы можете сделать что-то вроде этого, чтобы воспроизвести кнопку воспроизведения / остановки:

На вкладке network в ваших инструментах разработчика вы можете видеть потоковую передачу по частям, особенно если вы ограничиваете свое соединение.

Заключительное слово

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

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