在移动端IOS上获取video视频的第一帧为黑屏

在移动端IOS上获取video视频的第一帧为黑屏 ;代码如下:

/**
 * 获取视频的第一帧 来当做封面
 * @param url 是该文件的base64格式  返回值也是base64格式 可以直接使用
 */
export function getVideoBase64(url) {
  return new Promise(function (resolve, reject) {
      let dataURL = '';  // 最终得到的第一帧图片
      let width = '90';   // 截取图片的宽度 单位是px
      let height = '90'; // 截取图片的高度 单位是px
      let listen = 'loadeddata';  // 监听的是loadeddata事件
 
      let video = document.createElement('video');
      let canvas = document.createElement('canvas');
 
      video.setAttribute('crossOrigin', 'anonymous'); //处理跨域
      video.setAttribute('src', url);
      video.setAttribute('width', width);
      video.setAttribute('height', height);
      video.currentTime = 1; // 第一帧
      video.preload = 'auto'; //metadata:抓取原数据
 
       //判断是否是IOS设备        监听 durationchange或progress 在ios也会出现黑屏 
      if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
        video.load();  // 重新加载视频 解决在ios设备中 不会默认加载视频或音频资源的问题
        video.autoplay = true; // 设置自动播放
        video.muted = true;  // 静音
        listen = 'loadeddata'; // 当前帧的数据已加载 时触发
      }
      video.addEventListener(listen, () => {
        console.log('监听到了listen:', listen);
        canvas.width = width;
        canvas.height = height;
        canvas.getContext('2d').drawImage(video, 0, 0, width, height); //绘制canvas
        dataURL = canvas.toDataURL('image/jpeg'); //转换为base64
        resolve(dataURL);
      });
  });
}

首先需要了解 iOS 系统在处理视频的时候有一些特殊的要求,通常情况下,获取视频第一帧的方法是在 loadeddata 或 durationchange 事件触发后,将 video 元素的画面绘制到 canvas 中,然后通过 canvas.toDataURL() 方法将画布内容转换成 base64 格式的图片数据。

但是,在 iOS 环境下,当视频播放器尝试第一次自动播放或者被调用播放方法时,系统会对视频进行一个静音、暂停和不会自动播放的限制,以避免用户隐私泄漏,所以在 iOS 系统中获取视频第一帧通常是黑屏的情况。

为了解决这个问题,我们可以使用以下方法来获取视频第一帧:

  1. 判断是否是 iOS 系统。如果是则设置 video 元素的 autoplay 属性为 true,muted 属性为 true,并在 loadeddata 事件触发前加载资源。

  2. 监听 loadeddata 事件或 progress 事件。

  3. 将 video 元素的画面绘制到 canvas 中,然后通过 canvas.toDataURL() 方法将画布内容转换成 base64 格式的图片数据。

以下是示例代码:

/**
 * 获取视频第一帧的方法,并将画面转换成 base64 格式
 * @param {String} url 视频的 URL,可以是 base64 格式
 * @return {Promise} 一个 Promise 对象,返回值为视频第一帧的 base64 数据
 */
export function getVideoBase64(url) {
  return new Promise((resolve, reject) => {
    // 创建 video 元素
    const video = document.createElement('video');
    // 设置跨域属性
    video.crossOrigin = 'anonymous';
    // 设置视频 URL
    video.src = url;
    // 设置视频画面宽度
    video.width = '90';
    // 设置视频画面高度
    video.height = '90';
    // 设置视频播放位置为第一帧
    video.currentTime = 1;
    //设置预加载方式为自动加载
    video.preload = 'auto';

    // 创建 canvas 元素
    const canvas = document.createElement('canvas');
    // 将 canvas 的宽度和高度设置为视频画面的宽度和高度
    canvas.width = video.width;
    canvas.height = video.height;

    // 监听事件类型,默认为 loadeddata
    let listen = 'loadeddata';

    // 判断是否为 iOS 系统
    if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
      // 在 iOS 系统中,需要手动触发视频加载,然后设置自动播放和静音属性
      video.load();
      video.autoplay = true;
      video.muted = true;
      // 在 iOS 系统中,监听 canplaythrough 事件可以保证视频数据已经全部加载完毕
      listen = 'canplaythrough';
    }

    // 监听 video 元素的事件
    video.addEventListener(listen, () => {
      // 将视频画面绘制到 canvas 中
      canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
      // 将 canvas 转换成 base64 格式的图片数据,并通过 Promise 返回结果
      const dataURL = canvas.toDataURL('image/jpeg');
      resolve(dataURL);
    });
  });
}

黑屏的原因有可能是因为该视频的第一帧本身就是一个黑色图片