找回密码
 会员注册
查看: 188|回复: 0

附源码跨界救场:如何用纯前端的方式获取视频首帧

[复制链接]

5

主题

0

回帖

16

积分

新手上路

积分
16
发表于 2024-9-20 08:49:45 | 显示全部楼层 |阅读模式
背景最近在搬砖时遇到一个问题,在商详页面有些商品只有视频,没有封面图。我们的交互是用户点击视频封面图调用native播放器播放视频,没有封面图视频就没有了载体,就不能展示了。这个问题有3个解决方案后端处理:这种方案虽然可行,但是会影响接口性能,在商详这种关键页面得不偿失。客户端处理:客户端处理需要在进入商详页面前预加载视频,会影响页面响应速度,也不太合理。前端处理:前端处理必然会用到video标签来承载视频,考虑到video标签在移动端会有很多兼容性问题,处理起来很复杂,同时也会带来加载的性能消耗。基于上述三个方案,我们决定在源头解决这个问题,在创建商品时动态获取视频封面并保存。考虑到这是一个公共能力,我们把处理逻辑写成公共的npm包video-cover(https://www.npmjs.com/package/video-cover),有兴趣的可以去npm上下载和使用。接下来给大家分享一下这个包的实现方案和使用方法。进入正题效果展示首先我们看下实际使用效果。获取视频首帧整体过程是比较流畅的,当然,具体的获取时间取决于视频的质量和网速。整体思路动态创建video标签,加载视频。通过video的timeupdate事件来获取截取图片的时机。创建canvas画布,通过drawImage来绘制图像,然后通过toDataURL来导出图像信息。最后封装一些功能方法来方面使用。兼容性canvas对我们来说是一个熟悉又陌生的技术,在一些技术文档种经常有它的身影出现,但是业务中使用到的地方又不是很多。要使用这个技术,首先我们来看下兼容性,兼容性不好的话再好的技术也难以运用到业务中去。canvas兼容性从上图看来大部分浏览器兼容性没问题,话不多说,开始上代码代码展示首先我们要创建video标签,这步是关键,图像能不能截取成功就取决于视频能不能展示了。如果你使用的是网络图片,并且是跨域的。必须要设置video的crossOrigin='Anonymous',对此元素的CORS请求将不设置凭据标志。否则使用canvas的toDataURLapi会报错提示:Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported大概意思就是画布被污染。文档:参考文档[1]getVideoCover(callback) {    const self = this;    const video = this.video || document.createElement("video");    const currentTime = self.currentTime;    video.src = self.url;    video.style.cssText = `position: fixed; top: -100%; width: 400px; visibility: hidden;`;    video.controls = "controls";    // 此处是设置跨域,防止污染canvas画布    video.crossOrigin = "Anonymous";    // 设置视频播放进度    video.currentTime = currentTime;    // 监听播放进度改变,获取对应帧的截图    video.addEventListener("timeupdate", () => {        self.setVideoInfo();        if (self.currentTime  100) {              return true;          }      }      return false;  }base64转Blob对象。图片本地下载和保存到服务器都需要将base64转换成Blob对象。具体实现步骤为:  static base64ToBlob(code) {    if (!code) {      console.warn("base64不能为空");      return;    }    let parts = code.split(";base64,");    // 获取图片类型    let contentType = parts[0].split(":")[1];    /**      * 解码base64      * Window atob() 方法      *encodedStr: 必需,是一个通过btoa() 方法编码的字符串。      * 该方法返回一个解码的字符串。      */    let raw = window.atob(parts[1]);    let rawLength = raw.length;    //Uint8Array数组类型表示一个8位无符号整型数组,创建时内容被初始化为0。    let uInt8Array = new Uint8Array(rawLength);    // 将字符转换成unicode值    for (let i = 0; i  {      console.log(res)  })获取下一秒视频截图nextTime参数:无示例:cover.nextTime()获取指定位置视频截图jumpTime参数:@param{Number}time时间秒数示例:cover.jumpTime(20)最后试了一下,在chrome,firefox等主流浏览器都是可以的。由于video在移动端的兼容性不是很好,此插件适用于PC端。未来我们会兼容移动端,希望能在更多的平台得到运用。本文源码:https://github.com/18823752727/video-cover npm包地址:https://www.npmjs.com/package/video-cover参考文档:安全性和“被污染”的canvashttps://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_imageUint8Arrayhttps://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint8ArrayBlobhttps://developer.mozilla.org/zh-CN/docs/Web/API/Blob/BlobBase64的编码与解码https://developer.mozilla.org/zh-CN/docs/Glossary/Base64createObjectURLhttps://developer.mozilla.org/zh-CN/docs/Web/API/URL/createObjectURL
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 01:19 , Processed in 0.340467 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表