如何预览视频文件全部缩略图

2024/01/25 工作记录 共 2459 字,约 8 分钟

背景

实现在线视频剪辑,需要快速预览整个视频的大致内容,判断是否需要剪辑,功能类似剪映视频切割合并

成长记录(截取视频流关键帧有哪些方式?)

  1. 简单粗暴的方式:使用 video 标签,然后设置 currentTime 属性,把其作为图像源传给 canvasdrawImage 方法。即可取到关键帧的图片。只能取到你指定的时间点的图片,不能取到任意帧的图片

  2. 借用第三方库 MP4BoxWeb Codecs APIVideoDecoder 解码 得到 VideoFrame 相结合,读取整个视频文件的流。这种方式可以取到任意帧的图片

核心原理原理是 canvas 的绘制,利用他的 drawImage 方法,把画布的图像源设置为第一个参数,然后根据需要,进行设置别的参数。最后调用 toDataURL 方法,把画布内容转换为 base64 编码的 URL。图片就出来了

注意:

我们使用使用第二种方式实现,可能会遇到性能瓶颈。因为 MP4Box 会把整个视频文件的流读取到内存中,如果视频文件过大,可能会导致内存溢出, MP4Box 读取视频文件的速度也会影响到截取关键帧的速度。帧率越高,截取的速度越慢(帧率即每一秒钟有多少张图片一般情况是30)

VideoFrame 方式绘制视频关键帧(全量获取)

VideoFrame:是一个可传输的对象,表示某一帧,canvas 绘制的时候,他可以作为图像源。是 Web Codecs API 的 里面的概念,对浏览器的版本要求比较高.火狐浏览器不支持

VideoFrame 方式绘制视频关键帧 demo

当时遇到的问题

  1. 视频读关键帧乱序问题,初步怀疑流乱序问题,怀疑错误。流的读取肯定是按照顺序读取的,问题处在canvas绘制上,绘制会根据图片的大小不一致,绘制的快慢不一样。解决方案,读的时候全部推入数组里面,canvas绘制好了,在对比拿着此刻的流去那个数组里面找到对应的。或者直接使用回调函数

  2. 关键帧绘制到 canvas 上面的时候,我们使用了无损图片绘制,导致图片过大,性能不好。解决方案,使用两倍图的 jpeg 格式(即大小是我们设置canvas宽高度是我们展示图片容器宽高度的两倍)。这样可以减少图片的大小,提高性能

  3. 图像在canvas绘制结束,转 toBlob 效率会比转 base64 更快。blob 创建URL,用完记得释放内存

  4. 使用react 框架,频繁数据更新的时候,可以使用immer进行数据操作,因为太频繁的,用原生的更新很有可能出现更新不够及时

  5. 对下一个视频进行预加载,先 fetch 一下这个视频的链接,否则没办法进行预加载。下次解析的时候会更快

我们不需把每一帧都渲染到屏幕上,求视频的帧率,每秒渲染一张图就好了(比如帧率是30,那么每隔 30张取一张图渲染就好了)

webcodecs API

音频编解码:AudioDecoder/AudioEncoder/AudioData

图片编解码: ImageDecoder/ImageTrack/ImageTrackList

视频编解码:VideoDecoder/VideoEncoder/VideoFrame/VideoColorSpace

video 标签方式绘制视频关键帧(特定序列获取)

关键代码:

const video = document.createElement('video')
video.src = url
const canvas = document.getElementById('canvas');
const canvasCtx = canvas.getContext('2d');
video.currentTime = 60//截取第几秒的图片;
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
video.pause();
canvasCtx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, video.videoWidth, video.videoHeight);

注意点:

HTMLMediaElement: timeupdate :当 currentTime 更新时会触发 timeupdate 事件。这个事件的触发频率由系统决定,但是会保证每秒触发 4-66 次(前提是每次事件处理不会超过 250ms,延时在40~50ms之间)。因为 timeupdate 事件触发的频率不是固定的。随着 currentTime 定位的时间越发靠后,timeupdate 触发的时间间隔越来越长,甚至高达400多ms.这个速度显然是无法接受的。而且会影响很多后续的工作。比如我们不能保证在指定的时间点就能暂停视频的播放等之类的

前端操作视频文件

很少会有这样的需要,因为前端实现浏览器未必能带得动。假如有也是能实现的的,前提是你的电脑配置足够好。比如说修改视频的倍速,对视频文件进行增删改合并,添加蒙版,滤镜,画中画,镜像等等

简单说说预览图这块增删改合并的实现方案

  1. 每一段的视频的预览图都是数组的一项

  2. 当一个视频被切割成两个视频的时候,预览图数组的长度就变成2

  3. 每一组预览图的父元素的宽度跟时间相关,子元素图片自动填满当前宽度,利用margin-left来实现子元素的偏移量

  4. 当我们进行视频切割的时候,就能够完美的实现一张图片被一切成两张图片的效果。合并的时候,也能看到,一张图片被完美的合并成一张图片的效果

相关推荐

音频播放howler.js

AudioBuffer

波形图

音频剪裁,拼接,合并

FFmpeg视频合成插件推荐

总结

最开始拿到这个需求的时候脑瓜子嗡嗡的,毫无经验,所以那时候压力也很大,项目方又一直在催。但是现在回过头来看看,这个需求其实并不难,只是我当时没有经验,所以才会感到困难。所以,遇到困难的时候,不要怕,多问,多思考,多实践,总会有解决的办法的。

现在回过来看看,如果让我重新再来一遍,我可以实现的更好。可惜不可能了,只能说是,今后遇到复杂需求的时候的,应该要学会需求细分,分到不能分割为止。先思考想清楚了在下手,有必要的时候画流程图。


在技术的历史长河中,虽然我们素未谋面,却已相识已久,很微妙也很知足。互联网让世界变得更小,你我之间更近。

在逝去的青葱岁月中,虽然我们未曾相遇,却共同经历着一样的情愫。谁的青春不曾迷茫或焦虑亦是无奈,谁不曾年少过

在未来的日子里,让我们共享好的文章,共同学习进步。有不错的文章记得分享给我,我不会写好的文章,所以我只能做一个搬运工

我叫 sunseekers(张敏) ,千千万万个张敏与你同在,18年电子商务专业毕业,毕业后在前端搬砖

如果喜欢我的话,恰巧我也喜欢你的话,让我们手拉手,肩并肩共同前行,相互学习,互相鼓励

文档信息

Search

    Table of Contents