最近在做关于视频和图片上传的一些东西,之前也是经常做的功能,比较稀疏平常了,可是做一做发现用户体验可以上升一个档次,于是就开始研究 Video
标签来了
# Video 标签使用
标签没什么好说的,最好看看 MDN 的文档就可以了,给个基础的例子
<video controls width="250" src="./flower.mp4">
抱歉,您的浏览器不支持播放视频
</video>
# 提取几个比较常用的 API
height
视频展示区域的高度,单位是CSS像素。
width
视频显示区域的宽度,单位是CSS像素。
loop
布尔属性;指定后,会在视频结尾的地方,自动返回视频开始的地方。也就是传说中的循环播放
playsinline
一个布尔属性,标志视频将被“inline”播放,即在元素的播放区域内。请注意,没有此属性并不意味着视频始终是全屏播放的。
preload
该枚举属性旨在告诉浏览器作者认为达到最佳的用户体验的方式是什么。可能是下列值之一:
- none: 提示作者认为用户不需要查看该视频,服务器也想要最小化访问流量;换句话说就是提示浏览器该视频不需要缓存。
- metadata: 提示尽管作者认为用户不需要查看该视频,不过抓取元数据(比如:长度)还是很合理的。
- auto: 用户需要这个视频优先加载;换句话说就是提示:如果需要的话,可以下载整个视频,即使用户并不一定会用它。 空字符串:也就代指 auto 值。
假如不设置,默认值就是浏览器定义的了 (即,不同浏览器会选择自己的默认值),即使规范建议设置为 metadata。
- autoplay 属性优先于 preload 假如用户想自动播放视频,那么很明显浏览器需要下载视频。同时设置autoplay 和 preload属性在规范里是允许的。
- 规范没有强制浏览器去遵循该属性的值;这仅仅只是个提示。
src
要嵌到页面的视频的URL。可选;你也可以使用video块内的
autoplay
布尔属性;指定后,视频会马上自动开始播放,不会停下来等着数据载入结束。
controls
加上这个属性,Gecko 会提供用户控制,允许用户控制视频的播放,包括音量,跨帧,暂停/恢复播放。
# 常用的事件
canplay
浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不需要停止缓存更多的内容。
canplaythrough
浏览器估算可以播放到结束,不需要停止缓存更多的内容。
loadeddata
media 中的首帧已经加载。
# 兼容性
# 解析视频
直接上代码吧,这段代码创建 Video 元素,并且解析出来
function loadVideo(file) {
return new Promise(function(resolve, reject) {
// 三秒解析无结果判定无法解析头图和像素控制
let timer = setTimeout(() => {
reject("视频解析失败");
}, 3000);
const videoElement = document.createElement("video");
const dataUrl = URL.createObjectURL(file);
videoElement.onerror = function() {
clearTimeout(timer);
console.log(
"Error " +
videoElement.error.code +
"; details: " +
videoElement.error.message
);
reject("视频解析失败");
};
// IOS 测试了一下无法通过 preload 进行自动播放获取头图
if (isIPhone) {
// 需要设置 autoplay 来自动播放
videoElement.autoplay = true;
// 需要在行内播放,解决一下个别 APP 内部自动全屏开始播放的问题
videoElement.setAttribute("playsinline", true);
}
// 添加首帧监听事件
// 第一帧加载完成时触发
videoElement.addEventListener(
"loadeddata",
function() {
clearTimeout(timer);
resolve(videoElement);
},
false
);
// 设置 auto 预加载数据, 否则会出现截图为黑色图片的情况
videoElement.setAttribute("preload", "auto");
videoElement.src = dataUrl;
});
}
运行解析视频的代码,并且将首帧提取出来,并且可以校验视频的像素等
loadVideo(file)
.then((video) => {
// 校验视频像素
const minWideHigh = 500;
const width = video.videoWidth;
const height = video.videoHeight;
// 宽高为 0 代表失败,无法读取任何数据
if (width === 0 || height === 0) {
// 视频解析失败,无头图和像素校验
resolve();
return;
}
if (width < minWideHigh || height < minWideHigh) {
// your code ...
reject();
return;
}
// 校验通过后进行图片的头图解析以及数据初始化
const { videoWidth, videoHeight } = video;
const canvasElem = document.createElement("canvas");
canvasElem.width = videoWidth;
canvasElem.height = videoHeight;
canvasElem.getContext("2d").drawImage(video, 0, 0, videoWidth, videoHeight);
canvasElem.toBlob((blob) => {
const blobToDataURI = (blob, callback) => {
var reader = new FileReader();
reader.onload = function(e) {
callback(e.target.result);
};
reader.readAsDataURL(blob);
};
blobToDataURI(blob, (base64) => {
// 首帧以 base64 的形式获取到,做你该做的事
console.log(base64)
resolve();
});
}, "image/png");
})
.catch((error) => {
// your code ...
resolve();
});
没了