Javascript MediaStream同时捕获画布和音频

Javascript MediaStream同时捕获画布和音频,javascript,canvas,mediarecorder,mediastream,Javascript,Canvas,Mediarecorder,Mediastream,我正在从事一个项目,我想: 加载视频js并将其显示在画布上 使用过滤器来改变画布(以及视频)的外观 使用MediaStream captureStream()方法和MediaRecorder对象记录画布表面和原始视频的音频 在HTML视频元素中播放画布和音频流 通过调整此WebRTC演示代码,我能够在视频元素中显示画布录制: 也就是说,我不知道如何在画布旁边录制视频音频。是否可以创建包含来自两个不同源/元素的MediaStreamTrack实例的MediaStream 根据MediaStream

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

  • 加载视频js并将其显示在画布上
  • 使用过滤器来改变画布(以及视频)的外观
  • 使用MediaStream captureStream()方法和MediaRecorder对象记录画布表面和原始视频的音频
  • 在HTML视频元素中播放画布和音频流
  • 通过调整此WebRTC演示代码,我能够在视频元素中显示画布录制:

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

    根据MediaStream API的规范,理论上应该有一些方法来实现这一点:

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

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

    是的,你可以用这个方法

    但是Firefox只会在录制器中使用初始流的轨迹,直到修复为止


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

    • 要从画布获取视频流轨迹,可以调用方法

    • 要从视频元素获取音频流轨迹,可以使用WebAudioAPI及其方法。 这将返回包含音频流的MediaStreamDestination节点(
      dest
      )。然后,您必须将从视频元素创建的连接到此
      dest
      。 如果需要向该流添加更多音频曲目,则应将所有这些源连接到
      dest

    现在我们有了两个流,一个用于canvas视频,一个用于音频,我们可以在初始化之前使用
    canvasStream.addTrack(audioStream.getAudioTracks()[0])

    下面是一个完整的示例,现在只能在chrome中使用,可能很快就会在Firefox中使用,届时他们将修复该bug:

    var cStream,
    阿斯特拉姆,
    维德,
    录音机,
    分析仪,
    数据阵列,
    缓冲长度,
    块=[];
    函数clickHandler(){
    this.textContent='停止录制';
    cStream=canvas.captureStream(30);
    cStream.addTrack(aStream.getAudioTracks()[0]);
    记录器=新的媒体记录器(cStream);
    recorder.start();
    recorder.ondataavailable=saveChunks;
    recorder.onstop=exportStream;
    this.onclick=停止录制;
    };
    函数导出流(e){
    if(chunks.length){
    var blob=新blob(块)
    var vidURL=URL.createObjectURL(blob);
    var vid=document.createElement('video');
    vid.controls=真;
    vid.src=vidURL;
    vid.onend=函数(){
    revokeObjectURL(vidURL);
    }
    document.body.insertBefore(vid,canvas);
    }否则{
    document.body.insertBefore(document.createTextNode('no data saved'),canvas);
    }
    }
    函数存储块(e){
    e、 data.size&&chunks.push(e.data);
    }
    函数stopRecording(){
    参阅暂停();
    this.parentNode.removeChild(this);
    录音机。停止();
    }
    函数initAudioStream(evt){
    var audioCtx=新的AudioContext();
    //从AudioContext创建流
    var dest=audioCtx.createMediaStreamDestination();
    aStream=dest.stream;
    //将视频元素的输出连接到流
    var sourceNode=audioCtx.createMediaElementSource(此);
    sourceNode.connect(dest)
    //开始录像
    这个。play();
    //只是为了那些花哨的油画
    Analyzer=audioCtx.createAnalyzer();
    连接(分析仪);
    Analyzer.fftSize=2048;
    bufferLength=分析仪频率B计数;
    dataArray=新的Uint8Array(缓冲区长度);
    Analyzer.getByteTimeDomainData(数据数组);
    //输出到我们的耳机
    sourceNode.connect(audioCtx.destination)
    startCanvasAnim();
    rec.onclick=clickHandler;
    rec.disabled=false;
    };
    var loadVideo=函数(){
    vid=document.createElement(“视频”);
    vid.crossOrigin='匿名';
    vid.oncanplay=initAudioStream;
    vid.src=https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4';
    }
    函数startCanvasAnim(){
    //来自MDNhttps://developer.mozilla.org/en/docs/Web/API/AnalyserNode#Examples
    var canvasCtx=canvas.getContext('2d');
    canvasCtx.fillStyle='rgb(200200200200)';
    canvasCtx.lineWidth=2;
    canvasCtx.strokeStyle='rgb(0,0,0)';
    var draw=function(){
    var drawVisual=requestAnimationFrame(绘制);
    Analyzer.getByteTimeDomainData(数据数组);
    canvasCtx.fillRect(0,0,canvas.width,canvas.height);
    canvasCtx.beginPath();
    var sliceWidth=canvas.width*1.0/bufferLength;
    var x=0;
    对于(变量i=0;i
    
    
    太长了,读不下去了。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);
    // ...
    

    感谢您的快速响应和代码示例!很高兴知道,一旦错误得到解决,混合画布/音频流将是可行的(至少在Firefox中)。@dsing7,实际上chrome没有错误,我输入了一个错误(忘记将sourceNode连接到MediaStreamDestination…)修正了现在可以在Chrome上运行的代码。很高兴听到Chrome能按预期运行。比