gpt4 book ai didi

javascript - MediaStream 同时捕获 Canvas 和音频

转载 作者:可可西里 更新时间:2023-11-01 01:30:40 29 4
gpt4 key购买 nike

我正在从事一个项目,我想:

  1. 加载视频 js 并将其显示在 Canvas 上。
  2. 使用滤镜改变 Canvas (以及视频)的外观。
  3. 使用 MediaStream captureStream() 方法和 MediaRecorder 对象记录 Canvas 表面和原始视频的音频。
  4. 在 HTML 视频元素中播放 Canvas 和音频流。

通过调整以下 WebRTC 演示代码,我已经能够在视频元素中显示 Canvas 记录:https://webrtc.github.io/samples/src/content/capture/canvas-record/

就是说,我不知道如何在 Canvas 旁边录制视频的音频。是否可以创建一个包含来自两个不同源/元素的 MediaStreamTrack 实例的 MediaStream?

根据 MediaStream API 的规范,理论上应该有一些方法可以实现这一点: https://w3c.github.io/mediacapture-main/#introduction

“MediaStream API 中的两个主要组件是 MediaStreamTrack 和 MediaStream 接口(interface)。MediaStreamTrack 对象表示源自用户代理中一个媒体源的单一类型的媒体,例如网络摄像头生成的视频。 MediaStream 用于将多个 MediaStreamTrack 对象分组到一个单元中,该单元可以在媒体元素中记录或呈现。”

最佳答案

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

是的,您可以使用 MediaStream.addTrack() 来做到这一点方法,或 new MediaStream([track1, track2]) .


OP 已经知道如何获取所有这些,但这里提醒 future 的读者:

  • <canvas> 获取视频流轨道,您可以调用 canvas.captureStream(framerate) 方法。

  • <video> 获取音频流轨道您可以使用 Web Audio API 元素,它是 createMediaStreamDestination 方法。这将返回 MediaStreamAudioDestinationNode节点 ( dest ) 包含我们的音频流。然后你必须连接一个 MediaElementAudioSourceNode 从您的 <video> 创建元素,到这个dest .如果您需要向此流添加更多音轨,您应该将所有这些源连接到 dest .

现在我们有两个流,一个用于 <canvas>视频和音频,我们可以在初始化记录器之前将音轨添加到 Canvas 流中:

canvasStream.addTrack(audioStream.getAudioTracks()[0]);
const recorder = new MediaRecorder(canvasStream)

或者我们可以创建第三个 MediaStream来自这两个轨道的对象:

const [videoTrack] = canvasStream.getVideoTracks();
const [audioTrack] = audioStream.getAudioTracks();
const recordedStream = new MediaStream(videoTrack, audioTrack)
const recorder = new MediaRecorder(recordedStream);

这是一个完整的例子:

var
btn = document.querySelector("button"),
canvas,
cStream,
aStream,
vid,
recorder,
analyser,
dataArray,
bufferLength,
chunks = [];

function clickHandler() {

btn.textContent = 'stop recording';

if (!aStream) {
initAudioStream();
}

cStream = canvas.captureStream(30);
cStream.addTrack(aStream.getAudioTracks()[0]);

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

recorder.ondataavailable = saveChunks;

recorder.onstop = exportStream;

btn.onclick = stopRecording;

};

function exportStream(e) {

if (chunks.length) {

var blob = new Blob(chunks, { type: chunks[0].type });
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();
btn.remove();
recorder.stop();

}

function initAudioStream() {

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(vid);
sourceNode.connect(dest)
// start the video
vid.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();

}
function enableButton() {

vid.oncanplay = null;
btn.onclick = clickHandler;
btn.disabled = false;

};

var loadVideo = function() {

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

}

function startCanvasAnim() {
// from MDN https://developer.mozilla.org/en/docs/Web/API/AnalyserNode#Examples
canvas = Object.assign(document.createElement("canvas"), { width: 500, height: 200});
document.body.prepend(canvas);
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();
button { vertical-align: top }
<button disabled>record</button>

关于javascript - MediaStream 同时捕获 Canvas 和音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39302814/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com