当前位置: 首页 > 面试题库 >

MediaStream同时捕获画布和音频

毋琪
2023-03-14
问题内容

我正在一个项目中,我想要:

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

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

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


问题答案:

是否可以从两个不同的源/元素创建一个包含MediaStreamTrack实例的MediaStream?

是的,您可以使用MediaStream.addTrack()方法进行操作。

OP已经知道如何获取所有信息,但是在此提醒未来的读者:

  • 要从画布获取videoStream轨道,可以调用canvas.captureStream(framerate)method。

  • 要从视频元素获取音频streamTrack,可以使用WebAudio API及其createMediaStreamDestination方法。这将返回dest包含我们的audioStream 的MediaStreamDestination节点()。然后,您必须将根据您的视频元素创建[MediaElementSource连接到this dest。如果您需要向此流添加更多音轨,则应将所有这些源连接到dest

现在我们有了两个流,一个流用于画布视频,一个流用于音频,我们可以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,因此并不需要它,因此我们可以提供类似

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


 类似资料:
  • 如果您要为屏幕共享,语音备忘录等构建应用程序,音频和视频捕获是重要的特性。如果您需要应用程序来捕获配置文件图片,它们也很有用。 我们将使用getUserMedia HTML5 API通过Electron捕获音频和视频流。 让我们首先在main.js文件中设置我们的主进程,如下所示 - const {app, BrowserWindow} = require('electron') const ur

  • 问题内容: 我试着看看是否有办法用HTML5录制音频无济于事。但没有用。我猜他在说尚无任何浏览器支持时,确实是真的。 我想念什么吗?也许已经有可能?在基于浏览器的应用程序上录制音频有哪些选择? 请只开放源代码:) 问题答案: 你可能想看看HTML媒体捕获和它的API。 (注意:请注意,设备元素和相关的API在任何浏览器中均不可用,并且这些API可能会在此之前发生变化。)但是,它为您提供了一个大概的

  • export class SearchService { ... .map((response) => response.json()) .catch((e) => { if (e.status >== 500) { return cachedVersion(); new Error(`${ e.status

  • 本文向大家介绍HTML5中的MediaStream,包括了HTML5中的MediaStream的使用技巧和注意事项,需要的朋友参考一下 MediaStream表示媒体的同步流。如果没有音轨,它将返回一个空数组,并且将检查视频流;如果已连接网络摄像头,stream.getVideoTracks()将返回一个MediaStreamTrack数组,该数组表示来自网络摄像头的流。

  • 我正在考虑将我们内部的汽车/测量应用程序从Swing移植到JavaFX,主要是因为它有更好的外观和多点触控支持,但是我找不到一种方法来渲染只有当它们可见时才可以呈现的自定义组件。 为了获得动力,想象一个有10个选项卡的屏幕,每个选项卡内都有一个显示正在测量的一些实时数据的图。任何时候,只能看到一个情节。数据量很大,计算机有足够的能力一次渲染一个情节,但不能同时渲染所有情节。 摇摆版 现在在Swin

  • 我想以编程方式捕获内部音频。例如,我想(在我的设备上)播放一个音频文件,然后捕获音频输出,而不是在音量打开的情况下使用麦克风。 示例用例:我想制作一个其他开发者可以在游戏中使用的库,允许用户录制游戏中的音频。 Android说有回放捕获功能,但我只是找不到一个例子。我在谷歌上搜索了几个小时。每当我搜索“android捕获应用程序声音”或“androidrecordaudio”时,我要么会得到语音录