前端从视频文件提取画面帧

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 提取视频帧的过程相对较复杂,包括以下步骤:

  1. 解析容器文件到单独的编码视频和/或音频块:这个步骤需要将文件(例如 .mp4 文件)解析到单独的编码视频和/或音频块。

  2. 解码编码的视频/音频块: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。

以上就是文章全部内容了,如果喜欢这篇文章的话,还希望三连支持一下,感谢!

前端获取视频的第一是一个常见的需求,尤其是在需要生成缩略图或者预览图片的情况下。以下是实现这一功能的基本步骤: 1. **加载视频** 使用HTML5的`<video>`标签将目标视频文件引入到页面中,并通过JavaScript控制该元素。 2. **创建Canvas画布** 利用`<canvas>`元素,在视频播放开始之前或指定时间点提取当前画面内容并绘制到画布上。 3. **暂停视频并在第一位置捕获图像数据** 调用`currentTime = 0;`设置视频的时间轴回到初始状态(即第零秒),然后利用`pause()`方法停止视频播放。接下来借助 `drawImage(videoElement, x, y, width, height)` 将此时的画面复制至 canvas 上。 4. **导出静态图片** (可选) 如果你需要保存这个截图作为一张实际存在的图片,则可以进一步操作 Canvas 的上下文对象 ctx 来生成 base64 编码字符串表示形式的数据 URL (`toDataURL`) 或 Blob 文件。 ### 示例代码 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Extract Video First Frame</title> </head> <body> <video id="myVideo" src="example.mp4"></video> <canvas id="myCanvas" style="display:none;"></canvas> <script type="text/javascript"> const video = document.getElementById('myVideo'); const canvas = document.getElementById('myCanvas'); const context = canvas.getContext('2d'); function captureFrame() { // 设置宽度高度匹配视频尺寸 canvas.width = video.videoWidth; canvas.height = video.videoHeight; // 绘制第一个视频到canvas上面去 context.drawImage(video, 0, 0); return canvas.toDataURL(); // 可用于显示或下载 } // 当视频元数据已加载完成后再处理 video.addEventListener("loadeddata", () => { video.currentTime = 0; // 确保从最开头读取 setTimeout(() => { // 需等待渲染一再截屏 let frameDataUrl = captureFrame(); console.log(frameDataUrl); // 打印结果出来测试一下是否成功获得base64编码的image url. }, 100); }); video.load(); // 强行触发资源加载动作 </script> </body> </html> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小纯洁w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值