码上掘金不仅可以写 PPT,还可以录视频

sxkk20082年前知识分享209

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

前言

短视频作为新时代的产物,到现在才发展了几年的时间,创作者们看到了短视频的红利,有不少人已经通过视频录制和知识付费的方式实现了流量的变现,当然这只是一少部分人,还有成千上万的热涌向这个风口,他们在干什么?他们正在学习视频录制、视频剪辑的路上。

短视频的入门门槛虽然很低,但想要获得流量还是有一定门槛的,我今年的 flag 之一就是学习视频制作剪辑,前段时间剪了一个视频总共 1 分 20 秒,就花了我一整天的时间,那么我在想,作为前端工程师能不能开发一款产品,让短视频创作更低,后来我看到了一款贴合程序员的产品 Slidev,可以让我们使用 markdown 写 PPT,并且可以录制视频。

前端实现视频录制

好了,正文开始,本文基于我之前写的一篇文章《Markdown 写 PPT 是如何实现的?》,我们要在此之上实现视频录制的功能。

使用 WebRTC 的 API 可以实现了一个录音、录像、录屏工具

我们先使用 React 写一个录制的组件

import React, { useState, useRef } from 'react'
import ReactDom from 'react-dom'

const App = () => {
  const [videoUrl, setVideoUrl] = useState<string>('')

  // 结束
  const stopRecord = async () => {}

  // 开始
  const startRecord = async () => {}

  const pauseRecord = async () => {}

  const resumeRecord = async () => {}

  return (
    <div>
      <h1>React 录屏h1>
      <video className="video" src={videoUrl} controls />
      <h2>
        <button onClick={startRecord}>开始button>
        <button onClick={pauseRecord}>暂停button>
        <button onClick={resumeRecord}>恢复button>
        <button onClick={stopRecord}>停止button>
      h2>
    div>
  )
}

ReactDom.render(<App />, document.getElementById('app'))

上面有一个 video 标签,以及 开始、停止、暂停、恢复、几个按钮用于控制屏幕的录制。

const mediaStream = useRef<MediaStream>()
const audioStream = useRef<MediaStream>()
const recorder = useRef<MediaRecorder>()
const mediaBlobs = useRef<Blob[]>([])

我们使用 useRef 来存放数据,mediaStream 存放视频流, audioStream 存放音频流,recorder 存放视频录制对象,mediaBlobs 将流转化为 Blob 对象。

下面代码是开始录制和结束录制的逻辑:

// 结束
const stopRecord = async () => {
  recorder.current?.stop()
  // 不仅让 MediaRecorder 停止,还要让所有轨道停止
  mediaStream.current?.getTracks().forEach((track) => track.stop())
}

// 开始
const startRecord = async () => {
  // 录屏接口
  mediaStream.current = await navigator.mediaDevices.getDisplayMedia({ video: true })
  // 主动停止录制
  mediaStream.current?.getTracks()[0].addEventListener('ended', () => {
    stopRecord()
  })
  // 录音接口
  audioStream.current = await navigator.mediaDevices.getUserMedia({ audio: true })
  // 往视频流中加入音频流
  audioStream.current
    ?.getAudioTracks()
    .forEach((audioTrack) => mediaStream.current?.addTrack(audioTrack))
  // 录制视频流
  recorder.current = new MediaRecorder(mediaStream.current)

  // 将 stream 转成 blob 来存放
  recorder.current.ondataavailable = (blobEvent) => {
    mediaBlobs.current.push(blobEvent.data)
  }
  // 停止时生成预览的 blob url
  recorder.current.onstop = () => {
    const blob = new Blob(mediaBlobs.current, { type: 'video/mp4' })
    //来生成预览链接
    const mediaUrl = URL.createObjectURL(blob)
    setVideoUrl(mediaUrl)
  }

  recorder.current?.start()
}

上述代码先通过 navigator.mediaDevices.getDisplayMedia 获取用户选中的录屏流,接着通过 navigator.mediaDevices.getUserMedia({ audio: true })获取音频流,然后通过 mediaStream.current?.addTrack(audioTrack) 将所有音频流加入到视频流中。再通过 MediaRecorder 录制视频流,通过 ondataavailable 来存放当前流中的 Blob 数据。 最后一步,调用 URL.createObjectURL 来生成预览链接。

下面是暂停和恢复的实现代码,是 MediaRecorder 提供的方法

const pauseRecord = async () => {
  recorder.current?.pause()
}

const resumeRecord = async () => {
  recorder.current?.resume()
}

这样就实现了一个在线录屏的 Demo,一起在“码上掘金”中看看效果吧。

代码片段

实现幻灯片演讲录制

接下来我们将视频录制的功能集成到之前的幻灯片中,只需要将上面的 App 组件改成 RecordView 组件,并且通过 position: fixed; 属性将操作按钮定位到幻灯片之上。

录制完成后,通过创建一个 a 标签,就可以实现自动下载。

下面是自动下载的代码:

export function downloadBlob(blob, filename) {
  let element = document.createElement('a')
  element.setAttribute('href', blob)
  element.setAttribute('download', filename)
  element.style.display = 'none'
  document.body.appendChild(element)
  element.click()
  document.body.removeChild(element)
}

同样我们在“码上掘金”中看看效果吧。 代码片段 鼠标移动到左下角会显示操作按钮,我们还可以点击编辑按钮对幻灯片进行实时编辑,这么简单就实现了想要的效果,简直不可思议。

竖屏录制

目前短视频都是竖屏的,我们那么能否录制竖屏版的视频呢?答案是可以的,但是在“码上掘金”中不能,因为“码上掘金”是一个代码编辑器,在移动端无法访问,因此我还将这个应用部署到了 vercel 上,大家可以通过这个地址访问 :

http://ppt.runjs.cool/

打开 Chrome devtools 选择手机调试模式,选中一个合适的型号,便可以开始录制了,录制的时候选中当前网页就可以了。

竖屏录制

这样保存下来的视频便是竖屏的。

最后,我将这个工程的源码上传到了 GitHub:https://github.com/maqi1520/vitejs-md-ppt

目前还比较粗糙,经过精雕细琢后可能会成为一个好产品,先占个坑吧!

小结

本文用 WebRTC 的 API 简单地实现了一个录屏工具,并且可以结合 markdown 写 PPT 实现录制幻灯片的功能,我们一起来梳理下录屏的实现逻辑

  • 使用 getUserMedia 可获取麦克风以及摄像头的流;
  • 使用 getDisplayMedia 可获取屏幕的视频、音频流;
  • 使用 MediaRecorder 可监听 stream, 从而获取 Blob 数据;
  • 最后使用 URL.createObjectURLBlob 转为下载链接;

以上就是本文全部内容,如果对你有帮助,可以随手点个赞,这对我真的很重要,希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。

相关文章

流程图

全民分销流程图

Uniapp 实现全民分销功能

前言前段时间在掘金 app 多了一个推广中心,分享课程链接,若有其他用户从你分享的链接购买,你就可以获得一笔佣金,我们称类似的功能叫全民分销,全民分销在互联网推广中很常见,比如腾讯云、阿里云等都有,只...

这是启动后的界面,这个 demo 不是一个简单的页面,而是一个包含了深度嵌套路由的例子。

下图我开发时的截图,Turbopack 直接在命令行中打印出了构建时间,我们看到启动时间只需要 2.3ms

更新速度

试着修改代码,程序会自动热更新,绝大多数次数更新时间都很快,但偶尔有几次更新时间却很长,图片中有一处需要 16s(我使用的是 Mac M1),这其中的原因就不得而知了,尤大也发布了测评,使用 1000 个节点来对比更新速度,数据显示:根组件与 vite 时间几乎相同,叶子节点比 vite 快 68%,与官方称比 vite 快 10 倍相差甚远。当然目前 Turbopack 还处于 alpha 阶段,期待 Turbopack 能够尽快推出正式版。

Turbopack 特点

  • 开箱即用 TypeScript, JSX, CSS, CSS Modules, WebAssembly 等
  • 增量计算: Turbopack 是建立在 Turbo 之上的,Turbo 是基于 Rust 的开源、增量记忆化框架,除了可以缓存代码,还可以缓存函数运行结果。
  • 懒编译:例如,如果访问 localhost:3000,它将仅打包 pages/index.jsx,以及导入的模块。

为什么不选择 Vite 和 Esbuild?

Vite 依赖于浏览器的原生 ES Modules 系统,不需要打包代码,这种方法只需要转换单个 JS 文件,响应更新很快,但是如果文件过多,这种方式会导致浏览器大量级联网络请求,会导致启动时间相对较慢。所以作者选择同 webpack 一样方式,打包,但是使用了 Turbo 构建引擎,一个增量记忆化框架,永远不会重复相同的工作。

Esbuild 是一个非常快速的打包工具,但它并没有做太多的缓存,也没有 HMR(热更新),所以在开发环境下不适用。

你好,Next.js 13

theme: vuepress highlight: monokai文章为稀土掘金技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!前言上周发布了 Next.js 的一个...

智能家居技术:构建未来智慧家庭的人才需求与发展机遇

智能家居技术:构建未来智慧家庭的人才需求与发展机遇

  随着科技的不断进步与智能化的发展,智能家居已经成为了人们生活的一部分。智能家居技术的快速发展也带来了对相关行业的专业人才的需求。在这个快节奏的时代里,智能家居招聘市场正迅...

短链接生成器

用户小美: 微信加群二维码一到7天就过期,之前发过的用户,超过了这个时间没进来,又得重新发,每次真的重...

语音识别SDK:打造智能语音交互的先驱技术

语音识别SDK:打造智能语音交互的先驱技术

  随着科技的飞速发展,语音识别技术的普及越来越广泛,人们对于语音交互的需求也日益增长。而在这一领域中,语音识别SDK作为关键技术之一,正扮演着不可或缺的角色。本文将围绕语音...

AI机器人:实现人机交互的未来之源

AI机器人:实现人机交互的未来之源

  随着科技的不断发展,人工智能技术成为当今社会最具前景的领域之一。AI机器人作为人工智能技术的重要应用场景,正逐渐改变人类与机器的互动方式,开创了人机交互的未来之源。  A...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。