截取视频帧
方式:多媒体 + 画布 video+canvas
function captureVideo() {
const video:any = document.getElementById('video');
const canvas = document.createElement('canvas');
const ctx:any = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, video.clientHeight, video.clientWidth);
// 获取 base64
const dataUrl = canvas.toDataURL('image/png');
// 处理成File对象
const file = dataUrlToFile(dataUrl, '封面图.png');
file.then((res) => uploadFile(res));
}
// 上传文件对象到服务器
const uploadFile = async (file) => {
try {
// 创建FormData对象
const form = new FormData();
// 文件对象
form.append('fileData', file);
const data = await request(‘xxxx.json’, {
method: 'post',
name: "Filedata",
data: form,
});
console.log(data);
} catch (error) {
message.error(error.message || '上传失败,请重试');
}
}
// base64转成File对象
export async function dataUrlToFile(dataUrl: string, fileName: string): Promise {
const res: Response = await fetch(dataUrl);
const blob: Blob = await res.blob();
return new File([blob], fileName, { type: 'image/png' });
}
canvas.toDataURL()报错
原因:受限于 CORS 策略,会存在跨域问题,虽然可以使用图像(比如append到页面上)但是绘制到画布上会污染画布,一旦一个画布被污染,就无法提取画布的数据,比如无法使用使用画布toBlob(),toDataURL(),或getImageData()方法;当使用这些方法的时候 会抛出一个上面的安全错误
解决方式:给img或者video添加属性 crossOrigin:’anonymous’
img.setAttribute(‘crossOrigin’, ‘anonymous’);
Or
video.setAttribute(‘crossOrigin’, ‘anonymous’);
preload = ‘auto’
最好给video元素加上preload属性
视频裁剪
除了截取视频帧之外,还需根据特定比例对视频的进行裁剪
功能点:
1、裁剪实现
2、裁剪后预览
裁剪比例:
3 / 4 = 0.75
裁剪工具选择
react-rnd:https://github.com/bokuweb/react-rnd
在使用该工具过程中遇到了一个问题:如果使用缩放功能,边界控制会有问题(如下图);固定选择框宽高则无此问题,使用时需注意
裁剪后预览
通过reactRnd可以很方便的拿到裁剪参数,然后要根据这些参数,将裁剪后的区域在页面上展示
处理方案:CSS -> transform
使用transform后,裁剪区域的展示不成问题,但会有另一个问题出现:
多媒体播放器控制按钮的位置会随着裁剪区域变化而变化
目标:不管裁剪区域怎么变化,控制按钮位置不变,这就需要对控制按钮样式进行处理
/* step1:给父元素设置overflow:hidden样式,隐藏video超出区域 */
/* 父元素样式 */
.videoBox {
width: 256px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
:global {
video {
width: 100%;
max-height: 341px;
}
}
}
// halfScreenVideo: 获取多媒体播放器
const halfScreenVideo = document.querySelector('.half_screen');
// startY: 裁剪区y坐标
const { startY } = videoCutInfo;
/**
* 1.33: 缩放比 1 / 0.75
* 341: 预览高度,按宽度计算得到的值 256 / 0.75
* 35: 控制播放控制器位置
*/
// step2:改变转换原点 -> top
halfScreenVideo.style.transformOrigin = 'top';
// step3:根据比例先放大,根据裁剪区y坐标调整位置
halfScreenVideo.style.transform = `
translateY(${-(341 * startY * 1.33)}px) scale(1.33)`;
// step4:每次插入都会保留上一次插入的,因此需要先删除上一次插入的,保证只有一条样式规则
document.styleSheets[0].cssRules.length && document.styleSheets[0].deleteRule(0);
// step5:缩放到正常大小,设置多媒体控制器位置始终不变
document.styleSheets[0].insertRule(
`.half_screen::-webkit-media-controls{transform: translateY(
${341 * startY - 35}px) scale(0.75)}`,
0,
);