我正在一个项目中,我想要:
就是说,我不知道如何在画布旁边录制视频的音频。是否可以从两个不同的源/元素创建一个包含MediaStreamTrack实例的MediaStream?
“ MediaStreamAPI的两个主要组件是MediaStreamTrack和MediaStream接口。MediaStreamTrack对象表示一种单一类型的媒体,该媒体源自用户代理中的一个媒体源,例如网络摄像头产生的视频。MediaStream用于分组将多个MediaStreamTrack对象合并为一个单元,可以将其记录或呈现在媒体元素中。”_
是否可以从两个不同的源/元素创建一个包含MediaStreamTrack实例的MediaStream?
是的,您可以使用MediaStream.addTrack()方法进行操作。
MediaStream.addTrack()
OP已经知道如何获取所有信息,但是在此提醒未来的读者:
要从画布获取videoStream轨道,可以调用canvas.captureStream(framerate)method。
canvas.captureStream(framerate)
要从视频元素获取音频streamTrack,可以使用WebAudio API及其createMediaStreamDestination方法。这将返回dest包含我们的audioStream 的MediaStreamDestination节点()。然后,您必须将根据您的视频元素创建[MediaElementSource连接到this dest。如果您需要向此流添加更多音轨,则应将所有这些源连接到dest。
createMediaStreamDestination
dest
现在我们有了两个流,一个流用于画布视频,一个流用于音频,我们可以canvasStream.addTrack(audioStream.getAudioTracks()[0])在初始化之前使用newMediaRecorder(canvasStream)。
canvasStream.addTrack(audioStream.getAudioTracks()[0])
newMediaRecorder(canvasStream)
这是一个完整的示例,该示例现在仅在chrome中有效,并且可能很快将在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>
附言 :由于FF团队似乎需要花费一些时间来修复该错误,因此这里有一个快速修复使其也可以在FF上运行。
您也可以使用混合两个音轨newMediaStream([track1,track2])。但是,chrome当前为此构造函数添加了前缀,但由于它确实支持addTrack,因此并不需要它,因此我们可以提供类似
newMediaStream([track1,track2])
addTrack
var mixedStream = 'MediaStream' in window ? new MediaStream([cStream.getVideoTracks()[0], aStream.getAudioTracks()[0]]) : cStream; recorder = new MediaRecorder(mixedStream);