Невозможно перейти в поток с медиа-рекордера, используя медиа-источник с socket.io - PullRequest
1 голос
/ 09 мая 2019

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

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

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

Camera Client

main();
function main() {
    if (hasGetUserMedia()) {
        const constraints = {
            video: {
                facingMode: 'environment',
                frameRate: {
                    ideal: 10,
                    max: 15
                }
            },
            audio: true
        };

        navigator.mediaDevices.getUserMedia(constraints).
        then(stream => {
            setupRecorder(stream);
        });
    }
}

function setupRecorder(stream) {
    let mediaRecorder = new MediaRecorder(stream, {
        mimeType: 'video/webm; codecs="opus, vp9"'
    });

    mediaRecorder.ondataavailable = e => {
        var blob = e.data;
        socket.emit('video', blob);
    }

    mediaRecorder.start(500);
}

Сервер просто передает все, что получено

Наблюдение за клиентом

var sourceBuffer;
var queue = [];
var mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', sourceOpen, false);
main();

socket.on('stream', data => {
    if (mediaSource.readyState == "open") {
        if (sourceBuffer.updating || queue.length > 0) {
            queue.push(data.video);
        } else {
            sourceBuffer.appendBuffer(data.video);
        }
    }
});

function main() {
    videoElement = document.querySelector('#video');
    videoElement.src = URL.createObjectURL(mediaSource);
}

function sourceOpen(e) {
    console.log('open');
    sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="opus, vp9"');
    sourceBuffer.addEventListener('updateend', () => {
        console.log(sourceBuffer.updating, mediaSource.readyState);

        if (queue.length > 0 && !sourceBuffer.updating) {
            sourceBuffer.appendBuffer(queue.shift());
        }
    });
}

Таким образом, код на самом деле работает некорректно, поэтому с сервером отправки сокетов все в порядке. Это либо связано с MediaRecorder или MediaSource.

1 Ответ

0 голосов
/ 09 мая 2019

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

Правильно!

Чтобы решить эту проблему, вам нужно немного узнать о формате WebM. WebM - это всего лишь подмножество Matroska (MKV). Matroska - это спецификация схемы хранения мультимедиа в EBML. EBML - это двоичный формат файла, который может иметь произвольные блоки. Думайте об этом как о двоичном XML.

Это означает, что вы можете использовать такие инструменты, как EBML Viewer , чтобы проверять файлы WebM и ссылаться на спецификации Matroska, чтобы понять, что происходит. Например:

EBMLViewer Example

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

В каждом файле WebM есть два элемента верхнего уровня. EBML, который определяет этот двоичный файл, и Segment, который содержит все после.

В пределах Segment есть пара важных для вас элементов. Одним из которых является Tracks. Вы заметите, что в этом файле две дорожки: одна для аудио в Opus, а другая для видео в VP9. Другим важным блоком является Info, который содержит информацию о шкале времени и некоторые метаданные о мультиплексоре.

После всех этих метаданных вы найдете Cluster, Cluster, Cluster и т. Д. Это места, в которых вы можете вырезать поток WebM , при условии, что каждый Cluster начинается с ключевого кадра.

Другими словами, ваш код должен делать следующее:

  • Сохранить все данные перед первым Cluster как «данные инициализации».
  • Разделить на Cluster после этого.

При воспроизведении:

  • Используйте ранее сохраненные «данные инициализации» как первое, что вы загружаете.
  • Начните загрузку через Cluster с после этого, начиная с того места, где вы хотите в потоке.

Теперь важно знать, кому нужен кластерный бит. Насколько я знаю, нет способа настроить MediaRecorder для этого, и браузеры особенно требовательны к этому. Как минимум, вам придется перемаксовать на стороне сервера ... возможно, вам даже придется перекодировать. См. Также: Кодирование FFMPEG в MPEG-DASH - или WebM с кластерами ключевых кадров - для MediaSource API

с использованием медиаисточника с socket.io

Я должен отметить, что вам даже не нужен MediaSource для этого. Вам определенно не нужен Socket.IO. Это может быть так же просто, как вывод этих данных через обычный поток HTTP. Это загружается непосредственно в элементе <video>. (Обязательно используйте MediaSource, если вам нужен дополнительный контроль, но это не обязательно.)

...