Поток видео HTML5 из ​​веб-сокета через MediaSource и MediaSourceBuffer

Я пытаюсь воспроизвести видео из веб-сокета

<video id="output" width="320" height="240" autoplay></video>

<script>
    function sockets(buffer) {
        const socket = new WebSocket('wss://localhost:5002/ws')

        socket.onmessage = async function (event) {
            // event.data is a blob
            buffer.appendBuffer(new Uint8Array(event.data))
        }
    }

    let ms = new MediaSource()
    let output = document.getElementById('output')
    output.src = URL.createObjectURL(ms)
    ms.onsourceopen = () => {
        let buffer = ms.addSourceBuffer('video/webm; codecs="vorbis,vp8"')
        sockets(buffer)
    }
</script>

Я получаю здесь фрагменты MediaRecorder как Blobs и пытаюсь последовательно воспроизвести их с помощью MediaSource API. Ошибок нет и ничего не происходит. Что-то здесь не так?

Я пытался:

  • Использовать разные кодеки
  • Воспроизведение с режимами источника мультимедиа, например, последовательность / сегменты
  • Я также пробовал разные способы, когда вы не используете MediaSource API, но сталкиваетесь с другими проблемами, и MediaSource кажется лучшим подходом в моем случае.

ОБНОВЛЕНИЕ: вот как создается видео:

let options = { mimeType: 'video/webm;codecs=vp8' }
let stream = await navigator.mediaDevices.getUserMedia({ video: true })
mediaRecorder = new MediaRecorder(stream, options)
mediaRecorder.ondataavailable = event => {
    if (event.data && event.data.size > 0) {
        send(event.data)
    }
}

person Andrei    schedule 27.04.2020    source источник
comment
Как производится видео. какой кодек / контейнер? Что говорят внутренние устройства Chrome Media?   -  person szatmary    schedule 27.04.2020
comment
@szatmary Я обновил сообщение. Пожалуйста, взгляните   -  person Andrei    schedule 27.04.2020
comment
@Andrei Перейдите к chrome://media-internals, как предложено szatmary, чтобы получить дополнительную информацию. Кроме того, у вашего источника есть только видеопоток, но вы указываете видео- и аудиокодеки на принимающей стороне. Вы также не должны предполагать, что кодек, который вы получите от MediaRecorder, будет именно тем, который вы запросили. Используйте полученный mimeType на большом двоичном объекте.   -  person Brad    schedule 28.04.2020


Ответы (1)


Основная проблема здесь в том, что вы не можете передавать эти данные, исходящие из MediaRecorder, и ожидать, что другой конец их воспроизведет; это не полное видео. Это будет работать только в том случае, если принимающая сторона сможет получить байты инициализации - что я сомневаюсь, что это сработает в реальном сценарии.

Что вы можете сделать, так это создать интервал, который будет запускать / останавливать MediaRecorder, например, каждую 1 секунду, чтобы сделать 1-секундные фрагменты видео, которые вы можете передавать по сети (лучшее, что я знаю и протестировало, это веб-сокеты)

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

Взгляните на эту демонстрацию для справки: https://github.com/cyberquarks/quarkus-websockets-streamer/blob/master/src/main/resources/META-INF/resources/index.html

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

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

person quarks    schedule 28.04.2020
comment
Вы можете передавать данные из MediaRecorder в потоковом режиме и воспроизводить их позже. Это тривиально, особенно с WebM. Данные инициализации - это все до первого кластера. В вашем примере с интервалом нет гарантии работы ... запуск / остановка MediaRecorder является асинхронным и не обязательно падает в какой-то конкретный момент. В некоторых местах это может сработать для вас сегодня, но не обязательно. MediaRecorder отлично подходит для потоковой передачи в реальном времени. Низкая задержка - это требование не всех. Часто предпочтительнее не пропускать кадры и звук. - person Brad; 28.04.2020
comment
@ Брад, не могли бы вы подробнее рассказать об этом в ответе? Кажется, вы понимаете, о чем говорите :). Спасибо. - person Andrei; 28.04.2020
comment
@Andrei, вы можете заставить себя использовать MediaStream для потоковой передачи по сети, что возможно (никогда не говорил, что это невозможно), проблема, на которую я указываю, заключается в том, что вы не достигнете реального времени, вы можете искать по всему Stackoverflow, и никто не предлагает используя его в режиме реального времени. Если вам не нужен режим реального времени, то MediaRecorded - самый простой способ. - person quarks; 29.04.2020
comment
@Brad запуск / остановка работал для моей простой демонстрации, но снова никогда не использовал его, потому что он медленный, я даже спросил разработчиков Mozilla, и они сказали, что просто используйте холст в режиме реального времени. Однако вы упомянули, что MediaRecorder подходит для потоковой передачи в реальном времени, это ново, и если факт, то это здорово, есть ли у вас образец или демонстрация, которые могут это продемонстрировать? С тех пор, как я помню, я использовал MediaRecorder для нашего прототипа потоковой передачи в реальном времени, и причина, по которой я переключился на холст, заключается в том, что видео, которое излучает MediaRecorder, уже задерживается, насколько больше, если мы введем сетевую задержку. - person quarks; 29.04.2020
comment
@quarks Каковы ваши требования к задержке? С MediaRecorder не опускайтесь ниже секунды на кодировку. Если вам нужна низкая задержка, вам следует использовать WebRTC. Не всем требуется минимальная или низкая задержка. Если вы этого не сделаете, лучше отдать предпочтение качеству, что вы можете сделать с помощью MediaRecorder. - person Brad; 29.04.2020
comment
Вот старый пример кода: github.com/fbsamples/Canvas-Streaming-Example - person Brad; 29.04.2020
comment
@Brad Я смотрел ws.send(e.data); и увидел, что клиент отправляет данные прямо на сервер, теперь я понимаю, что вы имеете в виду, да, я думаю, что использование FFMPEG на сервере решит любую проблему потоковой передачи, поскольку он может обрабатывать входящий поток и разветвляться, но до сих пор в своих исследованиях я не видел, чтобы можно было сделать это на чистом Javascript. Как MediaRecorder --> websocket --> MediaSource без ffmpeg или чего-то еще, кроме сокета. - person quarks; 29.04.2020
comment
Вы можете сделать это без FFmpeg, передавая прямо в элемент <video>. Нет необходимости в расширениях MediaSource. Итак, MediaRecorder - ›Web Socket -› Passive Server - ›HTTP -› Video Element. Если вы действительно хотите перейти в прямой поток, вам просто нужны данные WebM до первого кластера, а затем начать с любого кластера, который начинается с ключевого кадра. Я сейчас не за компьютером, но есть еще один ответ Stack Overflow, где у меня есть подробности ... Я посмотрю, смогу ли я его найти завтра. - person Brad; 29.04.2020
comment
У меня аналогичная проблема, я могу транслировать видео в реальном времени через медиа-рекордер и веб-сокеты, но если кто-то заглянет в середину медиапотока, он не сможет увидеть видео. Я знаю, что требуются некоторые сегменты инициализации. Как это сгенерировать? - person Tarun Rawat; 19.05.2020
comment
Фактически, Canvas - плохое решение из-за его низкой эффективности и тратит впустую много системных ресурсов. - person MX-Qulin; 05.02.2021