2016-09-03 3 views
7

Я работаю над проектом, в котором я хотел бы:MediaStream Захват Canvas и аудио Одновременно

  1. Грузоподьемность видео JS и отображать его на холсте.
  2. Используйте фильтры, чтобы изменить внешний вид холста (и, следовательно, видео).
  3. Используйте метод captureStream() MediaStream и объект MediaRecorder для записи поверхности холста и звука исходного видео.
  4. Воспроизведение потока как холста, так и аудио в элементе HTML-видео.

Я был в состоянии показать запись холста в видеоэлементе щипая это WebRTC демонстрационного кода: https://webrtc.github.io/samples/src/content/capture/canvas-record/

То есть, я не могу понять, как записать аудио в видео; наряду с холстом , Возможно ли создать MediaStream, содержащий экземпляры MediaStreamTrack из двух разных источников/элементов?

Согласно спецификации в MediaStream API: есть теоретически должна быть какой-то способ сделать это:. https://w3c.github.io/mediacapture-main/#introduction

«Два основных компонента в API MediaStream являются интерфейсы MediaStreamTrack и MediaStream Объект MediaStreamTrack представляет носителе в один тип, который исходит от одного медиа-источника в User Agent, например, видео, созданного веб-камерой. MediaStream используется для группировки нескольких объектов MediaStreamTrack в один блок, которые могут быть записаны или отображены в медиа-элементе ».

+0

, поскольку принятый ответ не конкретно о p5.js, вы не возражаете, если я удалю его из названия и тела вашего вопроса? – Kaiido

+2

Совсем нет, иди за ним. – dsing7

ответ

11

Is it possible to create a MediaStream containing MediaStreamTrack instances from two different sources/elements?

Да, вы можете сделать это с помощью метода MediaStream.addTrack().

Но Firefox будет использовать дорожки начального потока только в рекордере, пока не будет исправлено this bug.


OP уже известно, как получить все это, но здесь является напоминанием для будущих читателей:

  • Чтобы получить видеопоток дорожки из холста, вы можете вызвать метод canvas.captureStream(framerate).

  • Чтобы получить аудиопоток из видеоэлемента, вы можете использовать API WebAudio и его метод createMediaStreamDestination. Это вернет узел MediaStreamDestination (dest), содержащий наш аудиопоток. Затем вам нужно будет подключить MediaElementSource, созданный с вашего видеоэлемента, к этому dest. Если вам нужно добавить больше аудиодорожек в этот поток, вы должны подключить все эти источники к dest.

Теперь, когда у нас есть два потока, один для холста видео и для аудио, мы можем использовать canvasStream.addTrack(audioStream.getAudioTracks()[0]) только перед инициализацией нашей new MediaRecorder(canvasStream).

Вот полный пример, который будет работать только в хроме сейчас, и, вероятно, в скором времени в Firefox, когда они исправили ошибку:

var cStream, 
 
    aStream, 
 
    vid, 
 
    recorder, 
 
    analyser, 
 
    dataArray, 
 
    bufferLength, 
 
    chunks = []; 
 

 
function clickHandler() { 
 

 
    this.textContent = 'stop recording'; 
 
    cStream = canvas.captureStream(30); 
 
    cStream.addTrack(aStream.getAudioTracks()[0]); 
 

 
    recorder = new MediaRecorder(cStream); 
 
    recorder.start(); 
 

 
    recorder.ondataavailable = saveChunks; 
 

 
    recorder.onstop = exportStream; 
 

 
    this.onclick = stopRecording; 
 

 
}; 
 

 
function exportStream(e) { 
 

 
    if (chunks.length) { 
 

 
    var blob = new Blob(chunks) 
 
    var vidURL = URL.createObjectURL(blob); 
 
    var vid = document.createElement('video'); 
 
    vid.controls = true; 
 
    vid.src = vidURL; 
 
    vid.onend = function() { 
 
     URL.revokeObjectURL(vidURL); 
 
    } 
 
    document.body.insertBefore(vid, canvas); 
 

 
    } else { 
 

 
    document.body.insertBefore(document.createTextNode('no data saved'), canvas); 
 

 
    } 
 
} 
 

 
function saveChunks(e) { 
 

 
    e.data.size && chunks.push(e.data); 
 

 
} 
 

 
function stopRecording() { 
 

 
    vid.pause(); 
 
    this.parentNode.removeChild(this); 
 
    recorder.stop(); 
 

 
} 
 

 
function initAudioStream(evt) { 
 

 
    var audioCtx = new AudioContext(); 
 
    // create a stream from our AudioContext 
 
    var dest = audioCtx.createMediaStreamDestination(); 
 
    aStream = dest.stream; 
 
    // connect our video element's output to the stream 
 
    var sourceNode = audioCtx.createMediaElementSource(this); 
 
    sourceNode.connect(dest) 
 
    // start the video 
 
    this.play(); 
 

 
    // just for the fancy canvas drawings 
 
    analyser = audioCtx.createAnalyser(); 
 
    sourceNode.connect(analyser); 
 

 
    analyser.fftSize = 2048; 
 
    bufferLength = analyser.frequencyBinCount; 
 
    dataArray = new Uint8Array(bufferLength); 
 
    analyser.getByteTimeDomainData(dataArray); 
 

 
    // output to our headphones 
 
    sourceNode.connect(audioCtx.destination) 
 

 
    startCanvasAnim(); 
 

 
    rec.onclick = clickHandler; 
 
    rec.disabled = false; 
 
}; 
 

 
var loadVideo = function() { 
 

 
    vid = document.createElement('video'); 
 
    vid.crossOrigin = 'anonymous'; 
 
    vid.oncanplay = initAudioStream; 
 
    vid.src = 'https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4'; 
 

 
    
 
} 
 

 
function startCanvasAnim() { 
 
    // from MDN https://developer.mozilla.org/en/docs/Web/API/AnalyserNode#Examples 
 
    var canvasCtx = canvas.getContext('2d'); 
 

 
    canvasCtx.fillStyle = 'rgb(200, 200, 200)'; 
 
    canvasCtx.lineWidth = 2; 
 
    canvasCtx.strokeStyle = 'rgb(0, 0, 0)'; 
 

 
    var draw = function() { 
 

 
    var drawVisual = requestAnimationFrame(draw); 
 

 
    analyser.getByteTimeDomainData(dataArray); 
 

 
    canvasCtx.fillRect(0, 0, canvas.width, canvas.height); 
 
    canvasCtx.beginPath(); 
 

 
    var sliceWidth = canvas.width * 1.0/bufferLength; 
 
    var x = 0; 
 

 
    for (var i = 0; i < bufferLength; i++) { 
 

 
     var v = dataArray[i]/128.0; 
 
     var y = v * canvas.height/2; 
 

 
     if (i === 0) { 
 
     canvasCtx.moveTo(x, y); 
 
     } else { 
 
     canvasCtx.lineTo(x, y); 
 
     } 
 

 
     x += sliceWidth; 
 
    } 
 

 
    canvasCtx.lineTo(canvas.width, canvas.height/2); 
 
    canvasCtx.stroke(); 
 

 
    }; 
 

 
    draw(); 
 

 
} 
 

 
loadVideo();
<canvas id="canvas" width="500" height="200"></canvas> 
 
<button id="rec" disabled>record</button>


Ps: Поскольку команда FF, похоже, занимает некоторое время, чтобы исправить ошибку, вот краткое решение, чтобы заставить ее работать и с FF.

Вы также можете смешивать две дорожки, используя new MediaStream([track1, track2]).
Однако, хром в настоящее время префиксы этот конструктор, но так как он поддерживает addTrack, это на самом деле не нужны, и мы можем прийти с чем-то, как некрасиво, как

var mixedStream = 'MediaStream' in window ? 
    new MediaStream([cStream.getVideoTracks()[0], aStream.getAudioTracks()[0]]) : 
    cStream; 
recorder = new MediaRecorder(mixedStream); 

Working fiddle for both FF and chrome.

+0

Благодарим вас за быстрый ответ и пример кода! Хорошо знать, что смешанные холсты/звуковые потоки будут осуществимы (по крайней мере, в Firefox) после исправления ошибки. – dsing7

+0

@ dsing7, на самом деле хром не имеет ошибки, я сделал опечатку (забыл подключить sourceNode к MediaStreamDestination ...) Исправлен код, который теперь работает в Chrome. – Kaiido

+0

Рад слышать, как работает Chrome, как и ожидалось. Спасибо за головы! – dsing7

 Смежные вопросы

  • Нет связанных вопросов^_^