Extraction pure du cadre frontal

Contexte

Récemment, lorsque je faisais des affaires, j'ai rencontré un besoin d'extraction de trame frontale. Après quelques recherches, je l'ai enregistré pour examen. L'exigence générale est de vous donner l'url de la vidéo et quelques nœuds temporels après avoir sauté de la page A à la page B. Nous devons extraire l'image de l'image de la vidéo à ces nœuds temporels et la rendre.

// 也就是说我们要实现这么一个函数 给你下面这样一个数据结构,返回一个对应时间节点的图像url
type Parms = {
    url:string;
    startTime:number[];
}
function getFrames(parmas:Parmas):string[]{

}
复制代码

Pour quelle raison? Pour le dire simplement, nous divisons une longue vidéo en plusieurs courtes vidéos, ce qui ressemble probablement à ce qui suit, mais cela prend trop de temps pour diviser une vidéo directement à l'avant, et il n'y a aucun moyen pour les utilisateurs de voir l'effet de la scission en temps réel. Choisissez donc la stratégie de démolition douce. La démolition douce signifie uniquement une division logique, en fournissant l'heure de début et l'heure de fin des clips vidéo qui doivent être divisés, puis en extrayant la première image de chaque clip vidéo. Lors de la lecture, le lecteur lit le clip vidéo correspondant Clips vidéo de nœuds temporels, le véritable travail fractionné se fait lentement en arrière-plan. De plus, cet article ne parle que du dessin de cadre, comment le jouer sera discuté dans le prochain article.

image.png

la solution

À l'heure actuelle, j'ai étudié deux solutions principales : 1. vidéo + toile 2, ffmpeg + webassembly

Comparez le pour et le contre

  1. vidéo + toile

Avantages : les attributs de l'élément vidéo effectuent des opérations de saut d'image et utilisent canvas pour dessiner l'image actuelle dans une image blob. L'ensemble du processus n'implique que le frontal, qui est simple et facile à utiliser.

Inconvénients : Il existe des problèmes de compatibilité avec certains formats de vidéos, qui ne peuvent pas être résolus en raison des limitations du navigateur ; il y aura du décalage pour les vidéos longues (plus d'une heure).

  1. ffmpeg + webassembly

Avantage : aucun problème de formatage

Inconvénients : Nécessite wasm, réserves de connaissances liées à ffmpeg, il y a une certaine difficulté à démarrer

L'entreprise limite le format vidéo de téléchargement à seulement mp4 ou mov, nous choisissons donc le schéma un ici ; pour le deuxième schéma, vous pouvez vous référer à l'article suivant : Extraction d'images vidéo basée sur ffmpeg+Webassembly

quelques points d'optimisation

  1. Préparer une vidéo basse résolution

    抽帧这事儿本身是为了让用户得到实时的体验,并不是最后视频拆分的结果,所以这里视频的分辨率要求不高,甚至可以说一定得低经测试400多M的视频分辨率降至480P后只有67M,因为视频越大抽帧越慢,这个应该比较容易想到。我们在业务中是用的480P的视频,这里选择一个基本能看清楚的分辨率就好了。

  2. 预抽帧

    这里预加载并不是有啥难度的事,仅仅是字面意思:在用户没有感知的情况下偷偷做抽帧的行为,用户点开后,直接展示已经抽好了的帧,剩下没有抽完的接着抽。那么问题来了,用户没有感知是一件很微妙的事,不同的业务都可能有所不同,总之是在用户做查看抽帧的图像这个行为之前都可以算作在预加载。

  3. 图片填充

    这里还有一个问题需要考虑,在抽帧没有完成前应该要为那些所有图像预留他们的位置,一个是防止滚动条不停的抖动;还有多少也能减少一点重排吧,这里是图片懒加载常用到的优化手段,大家应该蛮熟悉了。

抽帧具体实现

  1. 抽帧原理

    抽视频片段首帧实际上我们在干什么呢?我们要做的事就相当于打开一个播放器,把进度条拉到你需要截取的那一帧然后暂停,截图保存下来,重复以上操作;不过这里我们用代码来代替了这样的动作。这里其实也解释了为啥我们需要更小的视频,拉动 进度条 也就是改变video.currentTime时浏览器的视频解码器会搜索最接近指定时间位置的关键帧,分辨率越小视频存储的信息量也就越小,搜索也就越快。

  2. 初始化

    let video = document.createElement('video');
    let canvas = document.createElement('canvas');
    let ctx = canvas.getContext('2d');
    
    video.setAttribute('crossOrigin','Anonymous');//对此元素的 CORS 请求将不设置凭据标志。
    video.src = 'xxxx';
    video.onloadeddata = async()=>{
        xxx
    }
    复制代码

    loadeddata事件在媒体当前播放位置的视频帧(通常是第一帧)加载完成后触发。

  3. 抽帧

   video.onloadeddata = async () => {
      video.currentTime = 2;    // 相当于把进度条拉到2s
      let { videoWidth, videoHeight } = video;
      await new Promise((resolve, reject) => {
        video.onseeked = () => {
          resolve("seek resolve!"); //拉动进度条会触发seeked事件
        };
      });

      canvas.width = videoWidth;  //将画布的宽高和video的统一,否则会截不全
      canvas.height = videoHeight;
      await new Promise((resolve, reject) => {
        ctx.drawImage(video, 0, 0, videoWidth, videoHeight);
        canvas.toBlob((blob) => {  //方法名说明了一切 toBlob
          let url = URL.createObjectURL(blob); // 获取可以使用的url
          console.log("url", url);
          resolve(void 0);
        });
      });
    };
    
    //记得释放
    video = null;
    canvas = null;
复制代码

Ici, nous prenons l'image de la deuxième seconde comme exemple. Vous pouvez trouver une vidéo et l'essayer pour voir si l'url imprimée est comme prévu. En ce qui concerne la fonction createObjectURL, il convient de noter que l'url qu'elle génère est liée à la vie cycle du document, ce qui signifie que le rafraîchissement va baisser. . .

TG9fTMjESf.jpg

Il se trouve que nous avons toujours besoin que les utilisateurs reviennent sur cette page pour actualiser et maintenir les données, il est donc également nécessaire de vérifier la disponibilité de l'image et de générer une nouvelle image lors de l'actualisation, c'est-à-dire de redessiner le Cadre. Ici, nous expliquons brièvement comment vérifier si une image au format « blob : http://xxx » est disponible.

  1. Chèque

    Elle se décompose en deux étapes. Premièrement, vérifier si l'url commence par un blob. La deuxième étape consiste à créer une balise img et à lui ajouter l'url en tant qu'attribut src pour voir si elle déclenche un événement onload ou un événement onerror.

    async function checkImgAvailble(url) {
      const isAvailble = async() => {
        return new Promise((s, r) => {
          let img = new Image();
          img.src = url;
          img.onload = () => {
            s(true);
            img = null;
          };
          img.onerror = () => {
            s(false);
            img = null;
          };
        });
    
       
      };
      return /^blob:/.test(url) && (await isAvailble());
    }
    
    复制代码

essayer

Lors de la résolution du problème d'extraction lente des images dans les longues vidéos, nous avons trouvé un moyen de modifier l'espacement des images clés pour l'optimiser ; la clé de ce problème est le temps que prend le navigateur pour rechercher les images clés. Si l'intervalle des images clés est trop long, le le temps de recherche deviendra plus long. , et voici une scène fréquemment recherchée, nous pouvons donc réduire le temps de recherche en réduisant l'espacement des images clés ; plus précisément, l'espacement des images clés peut être contrôlé par le drapeau FFMPEGS -g. Pour plus de détails, voir : # Configurer pour le streaming vidéo à la recherche de performances .

Supongo que te gusta

Origin juejin.im/post/7155110617983451172
Recomendado
Clasificación