最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 谈谈MediaStream

    正文概述 掘金(62921)   2021-02-25   693

    MediaStream 是连接 WebRTC API 和底层物理流的中间层,webRTC将音视频经过Vocie / Video engine进行处理后,再通过MediaStream API给暴露给上层使用。 谈谈MediaStream

    概念

    • MediaStreamTrack
    • MediaStream
    • source
    • sink
    • MediaTrackConstraints

    1. MediaStreamTrack

    MediaStreamTrack是WebRTC中的基本媒体单位,一个MediaStreamTrack包含一种媒体源(媒体设备或录制内容)返回的单一类型的媒体(如音频,视频)。单个轨道可包含多个频道,如立体声源尽管由多个音频轨道构成,但也可以看作是一个轨道。 WebRTC并不能直接访问或者控制源,对源的一切控制都可以通过轨道控制MediaTrackConstraints进行实施。

    MediaStreamTrack MDN文档 MediaTrackConstraints MDN文档

    2. MediaStream

    MediaStream是MediaStreamTrack的合集,可以包含 >=0 个 MediaStreamTrack。MediaStream能够确保它所包含的所有轨道都是是同时播放的,以及轨道的单一性。

    MediaStream MDN文档

    3. source 与 sink

    再MediaTrack的源码中,MediaTrack都是由对应的source和sink组成的。

    //src\pc\video_track.cc
    void VideoTrack::AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, const rtc::VideoSinkWants& wants) {
      RTC_DCHECK(worker_thread_->IsCurrent());
      VideoSourceBase::AddOrUpdateSink(sink, wants);
      rtc::VideoSinkWants modified_wants = wants;
      modified_wants.black_frames = !enabled();
      video_source_->AddOrUpdateSink(sink, modified_wants);
    }
     
    void VideoTrack::RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) {
      RTC_DCHECK(worker_thread_->IsCurrent());
      VideoSourceBase::RemoveSink(sink);
      video_source_->RemoveSink(sink);
    }
    

    浏览器中存在从source到sink的媒体管道,其中source负责生产媒体资源,包括多媒体文件,web资源等静态资源以及麦克风采集的音频,摄像头采集的视频等动态资源。而sink则负责消费source生产媒体资源,也就是通过谈谈MediaStream,,等媒体标签进行展示,或者是通过RTCPeerConnection将source通过网络传递到远端。RTCPeerConnection可同时扮演source与sink的角色,作为sink,可以将获取的source降低码率,缩放,调整帧率等,然后传递到远端,作为source,将获取的远端码流传递到本地渲染。

    source 与sink构成一个MediaTrack,多个MeidaTrack构成MediaStram。

    4. MediaTrackConstraints

    MediaTrackConstraints描述MediaTrack的功能以及每个功能可以采用的一个或多个值,从而达到选择和控制源的目的。 MediaTrackConstraints 可作为参数传递给applyConstraints()以达到控制轨道属性的目的,同时可以通过调getConstraints()用来查看最近应用自定义约束。

    const constraints = {
      width: {min: 640, ideal: 1280},
      height: {min: 480, ideal: 720},
      advanced: [
        {width: 1920, height: 1280},
        {aspectRatio: 1.333}
      ]
    };
    
    //{ video: true }也是一个MediaTrackConstraints对象,用于指定请求的媒体类型和相对应的参数。
    navigator.mediaDevices.getUserMedia({ video: true })
    .then(mediaStream => {
      const track = mediaStream.getVideoTracks()[0];
      track.applyConstraints(constraints)
      .then(() => {
        // Do something with the track such as using the Image Capture API.
      })
      .catch(e => {
        // The constraints could not be satisfied by the available devices.
      });
    });
    

    如何播放MediaStream

    可将MediaStream对象直接赋值给HTMLMediaElement 接口的 srcObject属性。

    video.srcObject = stream;
    

    srcObject MDN文档

    如何获取MediaStream

    1. 本地设备

    可通过调用MediaDevices.getUserMedia()来访问本地媒体,调用该方法后浏览器会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。

    navigator.mediaDevices.getUserMedia(constraints)
      .then(function(stream) {
        /* 使用这个stream*/
        video.srcObject = stream;
      })
      .catch(function(err) {
        /* 处理error */
      });
    

    通过MediaDevices.enumerateDevices()我们可以得到一个本机可用的媒体输入和输出设备的列表,例如麦克风,摄像机,耳机设备等。

    //获取媒体设备
    navigator.mediaDevices.enumerateDevices().then(res => {
    	console.log(res);
    });
    

    谈谈MediaStream 列表中的每个媒体输入都可作为MediaTrackConstraints中对应类型的值,如一个音频设备输入audioDeviceInput可设置为MediaTrackConstraints中audio属性的值

    cosnt constraints = { audio : audioDeviceInput }
    

    将该constraint值作为参数传入到MediaDevices.getUserMedia(constraints)中,便可获得该设备的MediaStream。

    MediaDevices.enumerateDevices() MDN文档 MediaDevices.getUserMedia() MDN文档

    1. 捕获屏幕

    使用MediaDevices.getDisplayMedia()方法,可以提示用户去选择和授权捕获展示的内容或部分内容(如一个窗口),并将录制内容在一个MediaStream 里。

    谈谈MediaStream

    MediaDevices.getDisplayMedia() MDN文档

    1. HTMLCanvasElement.captureStream()

    使用HTMLCanvasElement.captureStream() 方法返回的 CanvasCaptureMediaStream 是一个实时捕获的canvas动画流。

    //frameRate设置双精准度浮点值为每个帧的捕获速率。
    //如果未设置,则每次画布更改时都会捕获一个新帧。
    //如果设置为0,则会捕获单个帧。
    cosnt canvasStream = canvas.captureStream(frameRate);
    video.srcObject = canvasSream;
    

    HTMLCanvasElement.captureStream() MDN文档 CanvasCaptureMediaStream MDN文档

    1. RTCPeerConnection

    2. 从其他MediaStream中获取

    可通过构造函数MediaStream() 返回新建的空白的 MediaStream 实例

    newStream = new MediaStream();
    
    • 传入 MediaStream 对象,该 MediaStream 对象的数据轨会被自动添加到新建的流中。且这些数据轨不会从原流中移除,即变成了两条流共享的数据。
    newStream = new MediaStream(otherStream);
    
    • 传入 MediaStreamTrack 对象的 Array 类型的成员,代表了每一个添加到流中的数据轨。
    newStream = new MediaStream(tracks[]);
    
    • MediaStream.addTrack()方法会给流添加一个新轨道。
    • MediaStream.clone()方法复制一份副本 MediaStream。这个新的MediaStream对象有一个新的id

    实现一个简易的录屏工具

    • 获取捕获屏幕的MeidaStream
    const screenStream = await navigator.mediaDevices.getDisplayMedia();
    
    • 获取本地音视频数据
    const cameraStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
    const audioStream = await navigator.mediaDevices.getUserMedia({ video: false, audio: true });
    
    • 将屏幕画面与摄像头画面绘制canvas中
    function createStreamVideo(stream) {
    	const video = document.createElement("video");
    	video.srcObject = stream;
    	video.autoplay = true;
    
    	return video;
    }
    
    const cameraVideo = createStreamVideo(cameraStream);
    const screenVideo = createStreamVideo(screenStream);
    
    animationFrameHandler() {
          if (screenVideo) {
              canvas.drawImage(screenVideo, 0, 0, canvasWidth, canvasHeight);
          }
    
          if (cameraVideo) {
              canvas.drawImage(
                  cameraVideo,
                  canvasWidth - CAMERA_VIDEO_WIDTH,
                  canvasHeight - CAMERA_VIDEO_HEIGHT,
                  CAMERA_VIDEO_WIDTH,
                  CAMERA_VIDEO_HEIGHT
              )
          }
    
          requestAnimationFrame(animationFrameHandler.bind(this));
      }
    
    • 获取canvas的MediaStream
    const recorderVideoStream = await canvas.captureStream();
    
    • 合并本地的音频轨道和canvasStream的视频轨道,获得最终画面的MediaStream
    const stream = new MediaStream();
    audioStream.getAudioTracks().forEach(track => stream.addTrack(track));
    recorderVideoStream.getVideoTracks().forEach(track => stream.addTrack(track));
    
    video.srcObject = stream;
    
    • 通过MediaRecorder对画面进行录制
    const recorder = new MediaRecorder(stream, { mineType: "video/webm;codecs=h264" });
    recorder.ondataavailable = e => {
    	recorderVideo.src = URL.createObjectURL(e.data);
    };
    
    //开始录制
    recorder.start();
    
    //停止录制
    recorder.stop();
    

    MediaRecorder MDN文档


    起源地下载网 » 谈谈MediaStream

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元