获取用户上传视频的第一帧图片(微信小程序环境)

注意

此方法已过时,ios能正常获取,安卓不行。

后面知道公司用的七牛云存储的资源。

直接在视频url后面拼接?vframe/jpg/offset/1就能获取到封面。

例如https://xxxxx.com/file/me/video.mp4?vframe/jpg/offset/1

其他oss平台也有对应的接口。

前言

需求:将用户上传的视频,截取封面图,然后上传给后端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 获取用户上传视频的第一帧图片(微信小程序环境)
export const getVideoFirstFrame = async (tempFilePath) => {
// 创建离屏canvas
const canvas = Taro.createOffscreenCanvas({ type: '2d' });

const context = canvas.getContext('2d');

// 创建解码器
const decoder = Taro.createVideoDecoder();

await decoder.start({
abortAudio: true,
source: tempFilePath,
});

let frameData;

// 等待开始解码
do {
await new Promise((resolve) => canvas.requestAnimationFrame(resolve));
frameData = decoder.getFrameData();
} while (!frameData);

// 设置 canvas 宽高
canvas.height = frameData.height;
canvas.width = frameData.width;

const startTime = Date.now();

const render = ({ data, width, height }) => {
const imageData = canvas.createImageData(data, width, height);
context.putImageData(imageData, 0, 0);
};

// 循环绘制解码结果 当缓冲区为空时,getFrameData可能返回null
do {
if (frameData && frameData.pkPts <= Date.now() - startTime) {
render(frameData);
frameData = null;
} else {
await new Promise((resolve) => canvas.requestAnimationFrame(resolve));
if (!frameData) frameData = decoder.getFrameData();
}
} while (!frameData);

// 将绘制的结果保存为图片
const imageBase64 = canvas.toDataURL();

// 将 base64 转为可用于uploadFile的临时文件路径
const fsm = Taro.getFileSystemManager();
const fileName = `${Date.now()}.png`;
const filePath = `${Taro.env.USER_DATA_PATH}/${fileName}`;

try {
// 移除 base64 头部信息
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '');
// 写入文件
fsm.writeFileSync(filePath, base64Data, 'base64');
// 上传文件
const res = await uploadFile(filePath);
// 清理临时文件
fsm.unlinkSync(filePath);

// 解码结束
await decoder.remove();
return res.url;
} catch (error) {
console.error('转换文件失败:', error);
await decoder.remove();
throw error;
}
};