B站视频卡片预览
打开浏览器控制台,当鼠标指向某个视频卡片时,会加载一张大图,这张图是当前视频许多帧的合集,所以视频预览的本质是预览图片,鼠标滑动时改变大图在容器的位置,就能实现这种效果。
视频预览实现
1、准备视频素材
下载地址:https://share.weiyun.com/Ps99dLfl
2、生成预览图
ffmpeg -i anoyi.mp4 -vf select='not(mod(n\,60))',scale=200:-1,tile=10x1 -frames:v 1 preview.png
preview 10x1
ffmpeg 命令解释说明:
-
select='not(mod(n\,60))'
:每60帧取1帧 -
scale=200:-1
:按宽度200等比缩放 -
tile=10x1
:取10帧合成1帧,排列顺序是 10x1(这里合成一行是为了方便后续前端计算)
如果做成和B站一样的形式,可以使用如下命令:
ffmpeg -i anoyi.mp4 -vf select='not(mod(n\,60))',scale=200:-1,tile=4x3:nb_frames=10 -frames:v 1 preview_4x3_10.png
preview 4x3
服务端源码参考(基于ffmpeg-python):
def get_scaled_preview_frame_by_frame(file_path: str, start, end, interval, count, width):
"""
获取缩放的视频帧
:param file_path: 视频地址
:param start: 起始帧数,默认值:0
:param end: 结束帧数,默认值:1
:param width: 缩放宽度,默认值:720
:param interval: 帧数间隔,默认值:1
:param count: 帧的数量,默认值:1
:return:
"""
out, err = (
ffmpeg
.input(file_path)
.filter('select', f'gte(n, {start})*lt(n, {end})')
.filter('select', f'not(mod(n, {interval}))')
.filter('scale', width, -1)
.filter('tile', f'{count}x1')
.output('pipe:', vframes=1, format='image2', vcodec='mjpeg', **{'q:v': 0})
.run(capture_stdout=True)
)
return out, err
3、前端实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Video Preview</title>
<style>
.video-bg {
height:100%; width: 100%; background-image: url(preview.png); background-repeat: no-repeat; background-position: 0 0;
}
</style>
</head>
<body style="margin:0; padding:0">
<div style="height: 100vh; width:100%;display: flex; align-items: center; justify-content:center">
<div style="width: 200px; height:113px; position: relative; cursor: pointer;" onmousemove="mouseMove(event)" onmouseout="mouseOut()">
<div class="video-bg" id="preview"></div>
</div>
</div>
</body>
<script>
// 节流与防抖
let ms = 200;
let lastEvent = Date.now() - ms;
const mouseMove = (event) => {
if (Date.now() - lastEvent >= ms) {
let offset = 200 * parseInt(event.offsetX / 20);
let style = `background-position: -${offset}px 0;`;
document.getElementById('preview').setAttribute('style', style);
lastEvent = Date.now();
}
}
const mouseOut = () => {
document.getElementById('preview').setAttribute('style', `background-position: 0 0;`);
}
</script>
</html>
4、效果预览
网友评论