1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/jmfe-jsmpeg

Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

JSMpeg – MPEG1 Video & MP2 Audio Decoder in JavaScript

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-элемента.

API JSMpeg.Player

Экземпляр JSMpeg.Player поддерживает следующие методы и свойства:

  • .play() – начать воспроизведение
  • .pause() – приостановить воспроизведение
  • .stop() – остановить воспроизведение и переместиться в начало
  • .nextFrame() – продвинуть воспроизведение на один кадр видео. Это не декодирует аудио. Возвращает true при успешном выполнении, false при недостатке данных.
  • .destroy() – останавливает воспроизведение, отключает источник и очищает состояние WebGL и WebAudio. Плеер не может быть использован после этого.
  • .volume – получить или установить громкость аудио (0-1)
  • .currentTime – получить или установить текущую позицию воспроизведения в секундах
  • .paused – только для чтения, указывает, приостановлено ли воспроизведение

Кодирование видео/аудио для JSMpeg

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 Мбит/с.

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

https://jsmpeg.com/perf.html

Потоковая передача через WebSockets

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 в маршрутизаторах блокирует публичные интернет соединения с вашей локальной сетью).

Коротко говоря, это работает так:

  1. Запустите websocket-relay.js
  2. Запустите ffmpeg, отправляя выход на порт HTTP ретранслятора
  3. Подключите JSMpeg в браузере к порту WebSocket ретранслятора

Пример настройки потокового вещания: Raspberry Pi реального времени камеры

В этом примере ffmpeg и WebSocket ретранслятор запускаются на одной системе. Это позволяет вам просматривать потоковое вещание в локальной сети, но не в интернете.

Этот пример предполагает, что ваша камера совместима с Video4Linux2 и отображается в файловой системе как /dev/video0. Большинство USB камер поддерживают стандарт UVC и должны работать нормально. Встроенная камера Raspberry Pi может быть использована как V4L2 устройство путем загрузки модуля ядра: sudo modprobe bcm2835-v4l2.

  1. Установите ffmpeg (см. Как установить ffmpeg на Debian / Raspbian). С помощью ffmpeg мы можем захватывать видео и аудио с камеры и кодировать их в MPEG1/MP2.

  2. Установите Node.js и npm (см. Установка Node.js на дистрибутивах Linux на основе Debian и Ubuntu для получения более новых версий). WebSocket ретранслятор написан на Node.js.

  3. Установите http-server. Мы будем использовать его для предоставления статических файлов (view-stream.html, jsmpeg.min.js), чтобы сайт с видео мог быть просмотрен в браузере. Любая другая веб-сервер тоже подойдет (nginx, apache и т.д.):

sudo npm -g install http-server

  1. Установите git и клонируйте этот репозиторий (или скачайте ZIP файл и распакуйте его):
sudo apt-get install git
git clone https://github.com/phoboslab/jsmpeg.git
  1. Перейдите в директорию jsmpeg/ cd jsmpeg/

  2. Установите Node.js WebSocket библиотеку: npm install ws

  3. Запустите WebSocket ретранслятор. Укажите пароль и порт для приема HTTP видеопотока и порт WebSocket для подключения из браузера: node websocket-relay.js supersecret 8081 8082

  4. В новом терминальном окне (все еще в директории jsmpeg/), запустите http-server для предоставления view-stream.html в браузер: http-server

  5. Откройте сайт потокового вещания в браузере. Http-server сообщит вам IP (обычно 192.168.[...]) и порт (обычно 8080), на которых он работает: http://192.168.[...]:8080/view-stream.html

  6. В третьем терминальном окне запустите 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. Он должен уменьшить задержку, но иногда это не работает при потоковой передаче видео и аудио — см. ниже.

Примечания о мультиплексировании ffmpeg и задержке

Добавление аудиопотока к 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 и внутренняя структура

Эта библиотека построена модульно с минимальными накладными расходами. Реализация новых демультиплексоров, декодеров, выходных устройств (рендереров, звуковых устройств) или источников должна быть возможной без изменения других частей. Однако вам все равно нужно будет подклассифицировать 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.

emcc компиляция

Используется версия 1.38.33

ffmpeg отправка

# Экран 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 )

Вы можете оставить комментарий после Вход в систему

Введение

модифицированная версия jsmpeg Развернуть Свернуть
MIT
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/jmfe-jsmpeg.git
git@api.gitlife.ru:oschina-mirror/jmfe-jsmpeg.git
oschina-mirror
jmfe-jsmpeg
jmfe-jsmpeg
master