JSMpeg — это видеоплеер, написанный на JavaScript. Он включает в себя демультиплексор MPEG-TS, декодеры MPEG1 видео и MP2 аудио, рендереры WebGL и Canvas2D, а также вывод звука через WebAudio. JSMpeg может загружать статические видео через Ajax и позволяет осуществлять потоковую передачу с низкой задержкой (~50мс) через WebSockets.
JSMpeg может декодировать видео 720p с частотой 30 кадров в секунду на iPhone 5S, работает в любом современном браузере (Chrome, Firefox, Safari, Edge) и занимает всего 20кб при сжатии gzip.
Использование может быть таким простым:
<script src="jsmpeg.min.js"></script>
<div class="jsmpeg" data-url="video.ts"></div>
Дополнительная информация и демонстрации: jsmpeg.com
Плеер JSMpeg можно создать в HTML, используя CSS-класс jsmpeg
для контейнера:
<div class="jsmpeg" data-url="<url>"></div>
или вызвав конструктор JSMpeg.Player()
напрямую в JavaScript:
var player = new JSMpeg.Player(url [, options]);
Обратите внимание, что использование HTML-элемента (внутренне JSMpeg.VideoElement
) предоставляет некоторые дополнительные функции по сравнению с JSMpeg.Player
. Например, кнопка паузы/воспроизведения в формате SVG и возможность "разблокировки" аудио на устройствах iOS.
Аргумент url
принимает URL-адрес файла MPEG .ts или WebSocket-сервера (ws://...).
Аргумент options
поддерживает следующие свойства:
canvas
– HTML-элемент Canvas для использования при рендеринге видео. Если не указан, рендерер создаст свой собственный элемент Canvas.loop
– следует ли повторять видео (только для статических файлов). По умолчанию true
.autoplay
- следует ли начать воспроизведение сразу (только для статических файлов). По умолчанию false
.audio
- следует ли декодировать аудио. По умолчанию true
.video
- следует ли декодировать видео. По умолчанию true
.poster
– URL-адрес изображения для использования в качестве постера до начала воспроизведения видео.pauseWhenHidden
– следует ли приостанавливать воспроизведение, когда вкладка неактивна. По умолчанию true
. Обратите внимание, что браузеры обычно замедляют выполнение JavaScript в неактивных вкладках.disableGl
- следует ли отключить WebGL и всегда использовать рендерер Canvas2D. По умолчанию false
.disableWebAssembly
- следует ли отключить WebAssembly и всегда использовать декодеры JavaScript. По умолчанию false
.preserveDrawingBuffer
– следует ли создавать контекст WebGL с preserveDrawingBuffer
- необходим для "скриншотов" через canvas.toDataURL()
. По умолчанию false
.progressive
- следует ли загружать данные по частям (только для статических файлов). При включении воспроизведение может начаться до полной загрузки источника. По умолчанию true
.throttled
- при использовании progressive
, следует ли откладывать загрузку частей, если они не нужны для воспроизведения. По умолчанию true
.chunkSize
- при использовании progressive
, размер части в байтах для загрузки за раз. По умолчанию 1024*1024
(1Мб).decodeFirstFrame
- следует ли декодировать и отображать первый кадр видео. Полезно для установки размера Canvas и использования кадра в качестве "постера". Это не имеет эффекта при использовании autoplay
или потоковых источников. По умолчанию true
.maxAudioLag
– при потоковой передаче, максимальная длина очереди аудио в секундах.videoBufferSize
– при потоковой передаче, размер буфера декодирования видео в байтах. По умолчанию 512*1024 (512кб). Возможно, придется увеличить это значение для очень высоких битрейтов.audioBufferSize
– при потоковой передаче, размер буфера декодирования аудио в байтах. По умолчанию 128*1024 (128кб). Возможно, придется увеличить это значение для очень высоких битрейтов.onVideoDecode(decoder, time)
– обратный вызов, который вызывается после каждого декодированного и отрисованного кадра видео.onAudioDecode(decoder, time)
– обратный вызов, который вызывается после каждого декодированного кадра аудио.onPlay(player)
– обратный вызов, который вызывается каждый раз при начале воспроизведения.onPause(player)
– обратный вызов, который вызывается каждый раз при паузе воспроизведения (например, при вызове .pause() или окончании источника).onEnded(player)
– обратный вызов, который вызывается при достижении конца источника (вызывается только при loop
= false
).onStalled(player)
– обратный вызов, который вызывается при недостатке данных для воспроизведения.onSourceEstablished(source)
– обратный вызов, который вызывается при первом получении данных от источника.onSourceCompleted(source)
– обратный вызов, который вызывается при получении всех данных от источника.Все опции, кроме canvas
, также можно использовать с HTML-элементом через атрибуты data-
. Например, чтобы указать повторение и автоматическое воспроизведение в JavaScript:
var player = new JSMpeg.Player('video.ts' {loop: true, autoplay: true});
или HTML
<div class="jsmpeg" data-url="video.ts"
data-loop="true" data-autoplay="true"></div>
Обратите внимание, что опции с верблюжьим регистром (camelCased
) должны быть разделены дефисами при использовании как атрибуты данных. Например, decodeFirstFrame: true
становится data-decode-first-frame="true"
для HTML-элемента.
Экземпляр JSMpeg.Player
поддерживает следующие методы и свойства:
.play()
– начать воспроизведение.pause()
– приостановить воспроизведение.stop()
– остановить воспроизведение и переместиться в начало.nextFrame()
– продвинуть воспроизведение на один кадр видео. Это не декодирует аудио. Возвращает true
при успешном выполнении, false
при недостатке данных..destroy()
– останавливает воспроизведение, отключает источник и очищает состояние WebGL и WebAudio. Плеер не может быть использован после этого..volume
– получить или установить громкость аудио (0-1).currentTime
– получить или установить текущую позицию воспроизведения в секундах.paused
– только для чтения, указывает, приостановлено ли воспроизведениеJSMpeg поддерживает воспроизведение контейнеров MPEG-TS с кодеком видео MPEG1 и кодеком аудио MP2. Декодер видео не корректно обрабатывает B-кадры (хотя современные кодировщики по умолчанию не используют их), а ширина видео должна быть кратна 2.
Вы можете закодировать подходящее видео с помощью ffmpeg следующим образом:
ffmpeg -i in.mp4 -f mpegts -codec:v mpeg1video -codec:a mp2 -b 0 out.ts
Вы также можете контролировать размер видео (-s
), частоту кадров (-r
), битрейт видео (-b:v
), битрейт аудио (-b:a
), количество каналов аудио (-ac
), частоту дискретизации (-ar
) и многое другое. Подробнее см. документацию ffmpeg.
Пример с подробными настройками:
ffmpeg -i in.mp4 -f mpegts \
-codec:v mpeg1video -s 960x540 -b:v 1500k -r 30 -bf 0 \
-codec:a mp2 -ar 44100 -ac 1 -b:a 128k \
out.ts
Хотя JSMpeg может обрабатывать видео 720p с частотой 30 кадров в секунду даже на iPhone 5S, учтите, что MPEG1 не так эффективен, как современные кодеки. MPEG1 требует значительной пропускной способности для HD видео. Видео 720p начинает выглядеть приемлемо при битрейте 2 Мбит/с (то есть 250кб/с). Кроме того, чем выше битрейт, тем больше работы выполняет JavaScript для его декодирования.
Это не должно быть проблемой для статических файлов или если вы передаете поток только в локальной Wi-Fi сети. Если вам не нужно поддерживать мобильные устройства, 1080p с битрейтом 10 Мбит/с работает отлично (если ваш кодировщик успевает). Для всех остальных случаев рекомендуется использовать разрешение 540p (960x540) с максимальным битрейтом 2 Мбит/с.
Вот сравнение производительности с различными разрешениями и включенными/выключенными функциями. Протестируйте это на целевых устройствах, чтобы понять, что можно использовать.
JSMpeg может подключаться к WebSocket-серверу, который отправляет двоичные данные MPEG-TS. При потоковой передаче JSMpeg пытается минимизировать задержку — он немедленно декодирует все доступные данные, игнорируя временные метки видео и аудио. Чтобы синхронизировать все (и минимизировать задержку), данные аудио должны часто чередоваться между кадрами видео (-muxdelay
в ffmpeg).
Отдельный режим буферизированной потоковой передачи, где JSMpeg предварительно загружает несколько секунд данных и представляет все с точным таймингом и синхронизацией аудио/видео, возможен, но пока не реализован.
Внутренние буферы для видео и аудио довольно малы (512кб и 128кб соответственно), и JSMpeg будет удалять старые (даже непроигранные) данные, чтобы освободить место для новых данных без особых проблем. Это может привести к артефактам декодирования при сетевом заторе, но обеспечивает минимальную задержку. Если необходимо, можно увеличить значения videoBufferSize
и audioBufferSize
.
JSMpeg оснащен небольшим WebSocket "ретранслятором", написанным на Node.js. Этот сервер принимает MPEG-TS источник через HTTP и передает его всем подключенным браузерам через WebSocket. Входящий HTTP поток можно генерировать с помощью ffmpeg, gstreamer или другими способами.
Разделение источника и WebSocket ретранслятора необходимо, так как ffmpeg не поддерживает протокол WebSocket. Однако это разделение также позволяет вам установить WebSocket ретранслятор на публичном сервере и делиться своим потоком в интернете (обычно NAT в маршрутизаторах блокирует публичные интернет соединения с вашей локальной сетью).
Коротко говоря, это работает так:
В этом примере ffmpeg и WebSocket ретранслятор запускаются на одной системе. Это позволяет вам просматривать потоковое вещание в локальной сети, но не в интернете.
Этот пример предполагает, что ваша камера совместима с Video4Linux2 и отображается в файловой системе как /dev/video0
. Большинство USB камер поддерживают стандарт UVC и должны работать нормально. Встроенная камера Raspberry Pi может быть использована как V4L2 устройство путем загрузки модуля ядра: sudo modprobe bcm2835-v4l2
.
Установите ffmpeg (см. Как установить ffmpeg на Debian / Raspbian). С помощью ffmpeg мы можем захватывать видео и аудио с камеры и кодировать их в MPEG1/MP2.
Установите Node.js и npm (см. Установка Node.js на дистрибутивах Linux на основе Debian и Ubuntu для получения более новых версий). WebSocket ретранслятор написан на Node.js.
Установите http-server. Мы будем использовать его для предоставления статических файлов (view-stream.html, jsmpeg.min.js), чтобы сайт с видео мог быть просмотрен в браузере. Любая другая веб-сервер тоже подойдет (nginx, apache и т.д.):
sudo npm -g install http-server
sudo apt-get install git
git clone https://github.com/phoboslab/jsmpeg.git
Перейдите в директорию jsmpeg/
cd jsmpeg/
Установите Node.js WebSocket библиотеку:
npm install ws
Запустите WebSocket ретранслятор. Укажите пароль и порт для приема HTTP видеопотока и порт WebSocket для подключения из браузера:
node websocket-relay.js supersecret 8081 8082
В новом терминальном окне (все еще в директории jsmpeg/), запустите http-server для предоставления view-stream.html в браузер:
http-server
Откройте сайт потокового вещания в браузере. Http-server сообщит вам IP (обычно 192.168.[...]
) и порт (обычно 8080
), на которых он работает:
http://192.168.[...]:8080/view-stream.html
В третьем терминальном окне запустите ffmpeg для захвата видеопотока с камеры и отправки его на WebSocket ретранслятор. Укажите пароль и порт (из шага 7) в целевом URL:
ffmpeg \
-f v4l2 \
-framerate 25 -video_size 640x480 -i /dev/video0 \
-f mpegts \
-codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \
http://localhost:8081/supersecret
Теперь вы должны видеть реальное изображение камеры в браузере.
Если ffmpeg не может открыть входное видео, возможно, ваша камера не поддерживает заданное разрешение, формат или частоту кадров. Чтобы получить список совместимых режимов, выполните:
ffmpeg -f v4l2 -list_formats all -i /dev/video0
Чтобы добавить аудио с камеры, просто вызовите ffmpeg с двумя отдельными входами.
ffmpeg \
-f v4l2 \
-framerate 25 -video_size 640x480 -i /dev/video0 \
-f alsa \
-ar 44100 -c 2 -i hw:0 \
-f mpegts \
-codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \
-codec:a mp2 -b:a 128k \
-muxdelay 0.001 \
http://localhost:8081/supersecret
Обратите внимание на параметр -muxdelay
. Он должен уменьшить задержку, но иногда это не работает при потоковой передаче видео и аудио — см. ниже.
Добавление аудиопотока к MPEG-TS иногда может привести к значительной задержке. Особенно это заметно при использовании ALSA и V4L2 на Linux (на macOS с AVFoundation проблем нет). Однако есть простое решение: просто запустите два экземпляра ffmpeg параллельно. Один для аудио, другой для видео. Оба выхода отправляются на один и тот же WebSocket ретранслятор. Благодаря простоте формата MPEG-TS правильное "мультиплексирование" двух потоков происходит автоматически внутри ретранслятора.
ffmpeg \
-f v4l2 \
-framerate 25 -video_size 640x480 -i /dev/video0 \
-f mpegts \
-codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \
-muxdelay 0.001 \
http://localhost:8081/supersecret
# В другом терминале
ffmpeg \
-f alsa \
-ar 44100 -c 2 -i hw:0 \
-f mpegts \
-codec:a mp2 -b:a 128k \
-muxdelay 0.001 \
http://localhost:8081/supersecret
В моих тестах USB камера добавила около ~180мс задержки, и кажется, что мы ничего не можем сделать с этим. Однако модуль камеры Raspberry Pi Camera Module обеспечивает более низкую задержку захвата видео.
Чтобы захватывать вход камеры на Windows или macOS с помощью ffmpeg, см. ffmpeg Capture/Webcam Wiki.
Эта библиотека построена модульно с минимальными накладными расходами. Реализация новых демультиплексоров, декодеров, выходных устройств (рендереров, звуковых устройств) или источников должна быть возможной без изменения других частей. Однако вам все равно нужно будет подклассифицировать JSMpeg.Player
, чтобы использовать любые новые модули.
См. исходный код jsmpeg.js, чтобы узнать, как модули взаимодействуют друг с другом и какие API они должны предоставлять. Я также написал статью о внутренней структуре JSMpeg: Decode It Like It's 1999.
Использование только части функционала библиотеки без создания полного плеера также должно быть относительно простым. Например, вы можете создать экземпляр класса JSMpeg.Decoder.MPEG1Video
, подключить рендерер к нему методом .connect()
, записать данные методом .write()
и декодировать кадры методом .decode()
, не затрагивая другие части JSMpeg.
В настоящее время версия JSMpeg в этом репозитории является полной переписью оригинальной библиотеки jsmpeg, которая могла декодировать только raw mpeg1video. Если вы ищете старую версию, см. тег v0.2.
Используется версия 1.38.33
# Экран mp4
ffmpeg -re -i ./demo.mp4 -an -f mpegts -codec:v mpeg1video -b:v 1500k -maxrate 2500k http://localhost:8081/wc
# Экран захвата
ffmpeg -f avfoundation -r 30 -i "Capture screen 0" -s 1230x800 -an -f mpegts -codec:v mpeg1video -codec:a mp2 -b:v 1500k -maxrate 2500k http://localhost:8081/wc
YUV player test
ffmpeg -re -i demo.mp4 -f rawvideo -c:v rawvideo -pix_fmt yuv420p -r 30 "http://localhost:9999/push?id=test&width=320&height=240"
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )