WebRTC MediaRecorder на удаленном потоке режет, когда поток зависает - PullRequest
1 голос
/ 24 марта 2019

Проблема:

Во время одноадресной видеоконференции WebRTC я могу успешно транслировать видео с веб-камеры мобильного устройства на ноутбук / настольный компьютер.Я хотел бы записать удаленный поток на стороне ноутбука / рабочего стола.(Настройка заключается в том, что мобильное устройство транслируется на ноутбук / компьютер).

Однако видео поток обычно время от времени зависает.Это не проблема, поскольку сторона «зрителя» наверстает упущенное.Однако запись удаленного потока остановится при первом зависании.

Минимальная и удаленная реализация (локальная запись):

Я могу успешно записать локальный поток из navigator.mediaDevices.getUserMedia() следующим образом:

const recordedChunks = [];

navigator.mediaDevices.getUserMedia({
    video: true,
    audio: false
}).then(stream => {
    const localVideoElement = document.getElementById('local-video');
    localVideoElement.srcObject = stream;
    return stream;
}).then(stream => {
    const mediaRecorder = new MediaRecorder(stream);
    mediaRecorder.ondataavailable = (event) => {
        if(event.data && event.data.size > 0) {
            recordedChunks.push(event.data);
        }
    };
    mediaRecorder.start({ mimeType: 'video/webm;codecs=vp9' }, 10);
});

Я могу легко загрузить это следующим образом:

const blob = new Blob(recordedChunks, { type: 'video/webm' });

const url = URL.createObjectURL(blob);
const a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = 'test.webm';
a.click();
window.URL.revokeObjectURL(url);

Минимальная и удаленная реализация (удаленная запись):

Используемая мной настройка требует записиУдаленный поток, а не локальный поток, для IOS Safari не поддерживает API MediaRecorder.Я включил выше, чтобы показать, что запись работает на локальной стороне.Реализация записи удаленного потока ничем не отличается, за исключением того, что я вручную добавляю звуковую дорожку с частотой 0 Гц к видео, поскольку в Chrome, как представляется, есть ошибка, из-за которой он не может записывать без звуковой дорожки.

const mediaStream = new MediaStream();
const audioContext = new AudioContext();

const destinationNode = audioContext.createMediaStreamDestination();

const oscillatorNode = audioContext.createOscillator();
oscillatorNode.frequency.setValueAtTime(0, audioContext.currentTime);
oscillatorNode.connect(destinationNode);

const audioTrack = destinationNode.stream.getAudioTracks()[0];
const videoTrack = remoteStream.getVideoTracks()[0]; // Defined somewhere else.

mediaStream.addTrack(videoTrack);
mediaStream.addTrack(audioTrack);

И затем я выполняю те же самые операции, что и в примере с локальным потоком, для записи переменной mediaStream.

Как уже упоминалось, в первой точке, где зависает удаленный поток (возможно, из-за задержки в сети)), удаленная запись прекращается, так что при загрузке продолжительность файла .webm, преобразованного в .mp4 через ffmpeg, составляет только то время, когда произошло первое зависание.

Попытки смягчить:

Одна попытка решить эту проблему, которую я пробовал, состоит в том, чтобы вместо записи удаленного потока, который достигается при обратном вызове для события ontrack из WebRTC, я используювместо этого поток видео с удаленного элемента видео через remoteVideoElement.captureStream().Это не работает, чтобы решить проблему.

Любая помощь будет принята с благодарностью.Спасибо.

1 Ответ

1 голос
/ 24 марта 2019

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

  1. Направьте входящий MediaStream к элементу видео.
  2. Используйте requestAnimationFrame() для планирования кадров рисования нахолст.(Обратите внимание, что это удаляет любое чувство genlock из исходного видео, и это не то, что вы хотите сделать. К сожалению, у нас нет способа узнать, когда происходят входящие кадры, насколько я знаю.)
  3. Используйте CanvasCaptureMediaStream в качестве источника видео.
  4. Перекомбинируйте видеодорожку из CanvasCaptureMediaStream вместе с аудиодорожкой из исходного MediaStream в новом MediaStream.
  5. Используйте этот новый MediaStream для MediaRecorder.

Я делал это с прошлыми проектами, где мне нужно было программно манипулировать аудио и видео.Это работает!

Одно большое предостережение в том, что в Chrome есть ошибка, из-за которой даже если поток захвата прикреплен к холсту, холст не будет обновляться, если вкладка не активна / не видна.И, конечно же, requestAnimationFrame в лучшем случае сильно ограничивается, если вкладка не активна, поэтому вам нужен другой источник кадровой синхронизации.(Я использовал аудио процессоры, ха!)

...