当视频能够预览并上传后,非要来一张视频第一帧的截图贴上,第一帧是黑的怎么办,下一帧。
一、文件上传
使用<input type="file">上传,change事件作为预览video的src的触发条件 新鲜源码:
<video controls width="700" height="300" src="" id="video"></video> <input type="file" id="input" hidden /> <button id="fileBtn">点击上传视频</button>
二、canvas截取图片
关于截取或者处理图片/视频/富文本编辑器,canvas是一个非常nice的选择。
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
附 Q&A:
网络上的常规理解是“在准备画布后,需要一些‘染料、画笔、绘图工具’的准备工作。” 比较官方的说话是返回canvas的上下文环境, 说人话是'你能够更好的操作你的canvas'。
方法中的2d参数目前可以理解为是固定参数,表示想要一个二维绘制环境。虽然大家都认为有2d自然应该有3d,然而实际上本身设计时也是这么考虑的,不过大家有点等不起了,所以都去选择webGL了。 webGL是啥?浏览器端借助系统显卡进行 3D 绘图。这是另一个故事了(IE别想了)。
返回一个CanvasRenderingContext2D对象,也就是上文所说的能够支持绝大多数对画布的操作。
// ctx.drawImage(file,sx,sy,swidth,sheight,x,y,width,height); ctx.drawImage(this, 0, 0, swidth, sheight);
在不需要剪裁的情况下,使用上述参数即截取操作file的全部,绘制到canvas上
关于参数(w3school) |参数 | 描述 | | :-------: |:-------------:| |file|规定要使用的图像、画布或视频。 |sx|可选。开始剪切的 x 坐标位置。 |sy|可选。开始剪切的 y 坐标位置。 |swidth|可选。被剪切图像的宽度。 |sheight|可选。被剪切图像的高度。 |x|在画布上放置图像的 x 坐标位置。 |y|在画布上放置图像的 y 坐标位置。 |width|可选。要使用的图像的宽度。(伸展或缩小图像) |height|可选。要使用的图像的高度。(伸展或缩小图像)
var src = canvas.toDataURL('image/jpeg');
关于toDataURL()方法。将canvas的内容导出
canvas.toDataURL(type, encoderOptions);
type: 图片格式,默认image/jpeg, encoderOptions:图片质量,取值范围为0到1,默认0.92。 返回值:包含 data URI 的DOMString,也就是base64格式。
三、截取视频第一帧
上传文件OK,用canvas截取OK,怎么找第一帧呢?(啥时候开始截取呢?)
当然是多媒体的事件来触发。 关于video的事件非常多(全部事件),这里只讨论能够影响到截取到第一帧的各个事件。
video.addEventListener('loadeddata', consoleString.bind(video, 'loadeddata')) // 当前帧加载完毕 video.addEventListener('loadedmetadata', consoleString.bind(video, 'loadedmetadata')) // 视频元数据加载完毕 video.addEventListener('canplay', consoleString.bind(video, 'canplay')) // 视频缓冲能够开始播放 video.addEventListener('timeupdate', consoleString.bind(video, 'timeupdate')) // 播放位置发生改变时 video.addEventListener('play', consoleString.bind(video, 'play')) // 开始播放时 video.addEventListener('waiting', consoleString.bind(video, 'waiting')) // 要播放下一帧而需要缓冲时 function consoleString(string) { console.log(string) } // 执行结果 // timeupdate // loadedmetadata // loadeddata // canplay // play(开始播放) // 没有waiting, 因为视频较小不需要缓冲
当currentTime更新时会触发timeupdate事件
来源:MDN
loadedmetadata的元数据恰好是指时长、尺寸(仅视频)以及文本轨道,也就是说在video未定义的时候currentTime是NaN或NULL,当元数据中时长加载完毕后,currentTime更新至0,因此触发。
结论:虽然最先触发,但是此时视频文件尚未加载,截取的是canvas的无内容本身。 注:timeupdate事件根据使用的系统不同,每秒触发4-66次,且由于触发频率高,单位过小(毫秒级别),事件响应需要延迟等原因,无法完全精准的控制。
文件、方法、事件都OK了。截就完事儿了。
video.addEventListener('loadeddata', function (e) { canvas.width = this.videoWidth canvas.height = this.videoHeight width = this.videoWidth height = this.videoHeight ctx.drawImage(this, 0, 0, width, height); var src = canvas.toDataURL('image/jpeg'); img.src = src; // var currentTime = this.currentTime // duration = this.duration // var fps = duration / 30 })