Day13 [实作] 把视讯及音讯内容录制下来

本篇我们将实作音视讯的录制并下载,内容包含:

  1. 录制影片

  2. 回放影片

  3. 下载影片

  4. 复制上一篇程序码

    cp -r take-a-photo video-recording
    
  5. index.html 中 将 video playbutton 替换为以下

    <div><video autoplay playsinline id="player"></video></div>
    <div><button id="shoot">拍照</button></div>
    

    替换为

    <div>
      <video autoplay playsinline id="player"></video>
      <video autoplay id="replayer"></video>
    </div>
    <div>
      <button id="shoot">拍照</button>
      <button id="record">录影</button>
      <button id="replay" disabled>回放</button>
      <button id="download" disabled>下载</button>
    </div>
    
    1. 加入一个 id 为 replayer 的 video
    2. 加入三个按钮 录影回放下载
  6. main.js 实作

    在原本的方法中增加 window.stream = stream

    // 将视讯显示在 video 标签上
    function gotStream(stream) {
      videoElement.srcObject = stream
    +  window.stream = stream  // 增加这段,录影需要取得stream
      return navigator.mediaDevices.enumerateDevices()
    }
    

    在後面加上录影的程序码:

    //record
    let buffer
    let mediaRecorder
    
    const recvideo = document.querySelector('video#replayer');
    const btnRecord = document.querySelector('button#record');
    const btnPlay = document.querySelector('button#replay');
    const btnDownload = document.querySelector('button#download');
    
    function handleDataAvailable(e) {
      if (e && e.data && e.data.size > 0) {
        buffer.push(e.data)
      }
    }
    
    function startRecord() {
      buffer = []
    
      var options = {
        mimeType: 'video/webm;codecs=vp8',
      }
    
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not supported!`)
        return
      }
    
      try {
        mediaRecorder = new MediaRecorder(window.stream, options)
      } catch (e) {
        console.error('Failed to create MediaRecorder:', e)
        return
      }
    
      mediaRecorder.ondataavailable = handleDataAvailable
      mediaRecorder.start(10)
    }
    
    function stopRecord() {
      mediaRecorder.stop()
    }
    
    btnRecord.onclick = () => {
      if (btnRecord.textContent === '录影') {
        startRecord()
        btnRecord.textContent = '停止'
        btnPlay.disabled = true
        btnDownload.disabled = true
      } else {
        stopRecord()
        btnRecord.textContent = '录影'
        btnPlay.disabled = false
        btnDownload.disabled = false
      }
    }
    
    btnPlay.onclick = () => {
      var blob = new Blob(buffer, { type: 'video/webm' })
      recvideo.src = window.URL.createObjectURL(blob)
      recvideo.srcObject = null
      recvideo.controls = true
      recvideo.play()
    }
    
    btnDownload.onclick = () => {
      var blob = new Blob(buffer, { type: 'video/webm' })
      var url = window.URL.createObjectURL(blob)
      var a = document.createElement('a')
    
      a.href = url
      a.style.display = 'none'
      a.download = 'video.webm'
      a.click()
    }
    

    题外话:检查浏览器支援哪些 Type

    可以在浏览器的 console 中输入以下

    function getSupportedMimeTypes() {
      const VIDEO_TYPES = ['webm', 'ogg', 'mp4', 'x-matroska']
      const VIDEO_CODECS = [
        'vp9', 'vp9.0', 'vp8', 'vp8.0', 'avc1', 'av1',
        'h265', 'h.265', 'h264', 'h.264', 'opus'
      ]
    
      const supportedTypes = []
      VIDEO_TYPES.forEach((videoType) => {
        const type = `video/${videoType}`
        VIDEO_CODECS.forEach((codec) => {
          const variations = [
            `${type};codecs=${codec}`,
            `${type};codecs:${codec}`,
            `${type};codecs=${codec.toUpperCase()}`,
            `${type};codecs:${codec.toUpperCase()}`,
            `${type}`,
          ]
          variations.forEach((variation) => {
            if (MediaRecorder.isTypeSupported(variation))
              supportedTypes.push(variation)
          })
        })
      })
      return supportedTypes
    }
    
    const supportedMimeTypes = getSupportedMimeTypes()
    console.log('Best supported mime types by priority : ', supportedMimeTypes[0])
    console.log(
      'All supported mime types ordered by priority : ',
      supportedMimeTypes,
    )
    

<<:  [Day 19] Mattermost - Webhooks

>>:  Makefile

D29 - 热点

分散式资料库理论上会把业务的loading平均分布到各个node上。但是仍有可能因为业务逻辑或者资料...

What's radiance?

目录 零、要讨论的主题 一、图解什麽是L 二、为什麽是L 三、参考资料 四、彩蛋 零、要讨论的主题 ...

Day05 捷径环境介绍

Hello 大家, 来到了连假的第三天, 时间消逝得太快... 总觉得还没有太放松假期就要结束了QQ...

Bloom效果,又或是高光效果

文章内使用Unity 2019 LTS 目标 Bloom效果 Bloom 以下这张图片也是一个常见...

分布式可观测性 Tracing、Time Series Data、LSM浅谈

上篇回顾 分布式可观测性 Logging 浅谈 分布式可观测性 Structured Log 分布式...