私がしたいプロジェクトに取り組んでいます:
このWebRTCデモコードを調整することで、ビデオ要素にキャンバスの記録を表示できました: https://webrtc.github.io/samples/src/content/capture/canvas-record/
とはいえ、キャンバスの横にビデオのオーディオを録音する方法がわかりません。 2つの異なるソース/要素からMediaStreamTrackインスタンスを含むMediaStreamを作成することは可能ですか?
MediaStream APIの仕様によると、理論的にはこれを実現するいくつかの方法があるはずです https://w3c.github.io/mediacapture-main/#introduction
"MediaStream APIの2つの主要コンポーネントは、MediaStreamTrackインターフェイスとMediaStreamインターフェイスです。MediaStreamTrackオブジェクトは、ユーザーエージェントの1つのメディアソースから発生する単一タイプのメディアを表します。 Webカメラ。MediaStreamを使用して、複数のMediaStreamTrackオブジェクトを1つのユニットにグループ化し、メディア要素で記録またはレンダリングできます。 "
2つの異なるソース/要素からMediaStreamTrackインスタンスを含むMediaStreamを作成することは可能ですか?
はい、 MediaStream.addTrack()
メソッドを使用して実行できます。
ただし、Firefoxは このバグ が修正されるまで、レコーダーへの初期ストリームのトラックのみを使用します。
OPはそれをすべて取得する方法をすでに知っていますが、今後の読者へのリマインダーです:
キャンバスからvideoStreamトラックを取得するには、 canvas.captureStream(framerate)
メソッドを呼び出します。
ビデオ要素からオーディオstreamTrackを取得するには、WebAudio APIを使用できます createMediaStreamDestination
メソッド。これは、audioStreamを含むMediaStreamDestinationノード(dest
)を返します。次に、ビデオ要素から作成された MediaElementSource をこのdest
に接続する必要があります。このストリームにさらにオーディオトラックを追加する必要がある場合は、これらすべてのソースをdest
に接続する必要があります。
キャンバスビデオ用とオーディオ用の2つのストリームを取得したので、 canvasStream.addTrack(audioStream.getAudioTracks()[0])
を初期化する直前にnew MediaRecorder(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>
_
Ps:FFチームはバグを修正するのに時間がかかるようですので、FFでも動作するようにすばやく修正します。
new MediaStream([track1, track2])
を使用して2つのトラックを混在させることもできます。
ただし、chromeは現在このコンストラクタにプレフィックスを付けていますが、addTrack
をサポートしているため、実際には必要ありません。
_var mixedStream = 'MediaStream' in window ?
new MediaStream([cStream.getVideoTracks()[0], aStream.getAudioTracks()[0]]) :
cStream;
recorder = new MediaRecorder(mixedStream);
_
Kaiidoのデモは素晴らしいです。 tl; drコードを探して、オーディオストリームを既存のキャンバスストリームに追加するだけの場合:
let videoOrAudioElement = /* your audio source element */;
// get the audio track:
let ctx = new AudioContext();
let dest = ctx.createMediaStreamDestination();
let sourceNode = ctx.createMediaElementSource(videoOrAudioElement);
sourceNode.connect(dest);
sourceNode.connect(ctx.destination);
let audioTrack = dest.stream.getAudioTracks()[0];
// add it to your canvas stream:
canvasStream.addTrack(audioTrack);
// use your canvas stream like you would normally:
let recorder = new MediaRecorder(canvasStream);
// ...