extractFramesFromVideo方法提取画面帧
// 设定一个异步函数,输入参数为:
// videoUrl(需要提取画面帧的视频的URL)
// fps(每秒帧率,默认为25帧)
async function extractFramesFromVideo(videoUrl, fps = 25) {
// 我们使用 Promise 将该函数设置为异步操作
return new Promise(async (resolve) => {
// 使用 fetch 函数从视频URL获取数据,并将其转换为 Blob 对象
let videoBlob = await fetch(videoUrl).then((r) => r.blob());
// 创建一个对应 Blob 对象的 URL
let videoObjectUrl = URL.createObjectURL(videoBlob);
// 创建一个 HTML video 的新实例
let video = document.createElement("video");
// 定义一个新变量,在后面的 "seeked" 事件中赋值
let seekResolve;
// 当 "seeked" 事件触发,我们确认视频已经被加载到了特定的时间点
video.addEventListener("seeked", async function () {
if (seekResolve) seekResolve(); // 执行我们的 Promise 结束指令
});
// 将我们的视频 URL 设置为创建的 video 对象
video.src = videoObjectUrl;
// 我们等待视频加载,一旦加载成功,则能获取到视频的长度信息
while ((video.duration === Infinity || isNaN(video.duration)) &&
video.readyState < 2) {
await new Promise((r) => setTimeout(r, 1000)); // 等待 1000ms
video.currentTime = 10000000 * Math.random(); // 用一个随机的时间进行跳跃
}
// 获取视频长度
let duration = video.duration;
// 创建 canvas 对象和 2d 上下文进行画面帧的绘制
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
let [w, h] = [video.videoWidth, video.videoHeight]; // 获取视频的宽度和高度
canvas.width = w;
canvas.height = h;
// 初始化一个数组用于存放提取出来的帧的数据
let frames = [];
let interval = 1 / fps; // 根据帧率(fps)计算间隔时间
let currentTime = 0; // 初始化当前的播放时间
// 从视频开始提取画面帧,直到视频的末尾
while (currentTime < duration) {
video.currentTime = currentTime; // 设置视频的当前播放时间
await new Promise((r) => (seekResolve = r)); // 等待 "seeked" 事件完毕
context.drawImage(video, 0, 0, w, h); // 将当前画面帧绘制到 canvas 上
let base64ImageData = canvas.toDataURL(); // 获取绘制的图片数据
frames.push(base64ImageData); // 将提取的画面帧加入到 frames 数组中
currentTime += interval; // 将当前时间增加一个间隔时间
}
// 返回所有提取的画面帧
resolve(frames);
});
}
调用方式将视频URL作为参数传递给该函数:
let frames = await extractFramesFromVideo(‘http://example.com/example.mp4’, 25);
在这里,‘http://example.com/example.mp4’ 是视频的 URL,25 是你希望每秒提取的帧数。函数将返回一个数组,其中包含了一系列从视频中提取的画面帧(以 base64 编码的图片形式)。
WebCodecs API 提取视频帧
…WebCodecs API 提取视频帧的过程相对较复杂,包括以下步骤:
-
解析容器文件到单独的编码视频和/或音频块:这个步骤需要将文件(例如 .mp4 文件)解析到单独的编码视频和/或音频块。
-
解码编码的视频/音频块:WebCodecs 仅仅方便了这个过程中的解码步骤。你需要自己实现解析/处理容器文件的过程。
在这个过程中, MP4Box它能帮你获取编码的视频和音频块,然后你可以将这些块输入到 VideoDecoder 或 AudioDecoder。
使用 MP4Box,你的代码可能会围绕 onSamples 回调实现,大概如下所示:
mp4BoxFile.onSamples = (trackId, user, chunks) => {
for (let i = 0; i < chunks.length; i++) {
let chunk = chunks[i];
let encodedChunk = new EncodedVideoChunk({
// you'll need to deep-inspect chunk to figure these out
type: "key", // or "delta"
timestamp: ...,
duration: ...,
data: chunk.data
});
// pass encodedChunk to a VideoDecoder instance's decode method
}
};
以上是利用 WebCodecs API 提取视频帧的大体步骤,对于具体的应用细节可能需要根据你的具体需求进行调整。
mp4BoxFile是使用了MP4Box.js库的一个示例。MP4Box.js 是一个 JavaScript 库,用于处理 MP4 文件,特别是在浏览器端。
这个库提供了一个MP4Box类,你可以用new MP4Box.createFile()来创建一个mp4BoxFile。然后,你可以添加自定义的回调,例如 onReady 和 onSamples,然后向对象提供ArrayBuffer类型的数据。这个库支持逐步解析文件,所以你可以一边下载文件一边进行解析。
例如:
var mp4boxfile = MP4Box.createFile();
mp4boxfile.onReady = info => {
// do something when file is ready
};
mp4boxfile.onSamples = (trackId, user, samples) => {
// do something with samples
};
// append data
mp4boxfile.appendBuffer(someArrayBufferData);
这个库可以帮助你从 MP4 文件中提取出音频和视频块,然后你可以将这些编码的块传递给 VideoDecoder 或者 AudioDecoder。
以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!