首页 > 其他分享 >webcodecs mix-blend-mode

webcodecs mix-blend-mode

时间:2024-05-06 20:12:24浏览次数:20  
标签:canvas const videoTrack mp4box videoFrame mix webcodecs video blend

WebCodecs mix-blend-mode: screen 混合模式


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .bg,
      .video,
      .canvas {
        width: 200px;
        height: auto;
        object-fit: contain;
        box-sizing: border-box;
      }
    </style>
  </head>
  <body>
    <img src="./school_overcast-s.jpg" alt="" class="bg" />
    <video src="./fire.mp4" controls autoplay loop muted class="video"></video>
    <canvas class="canvas"></canvas>

    <script src="./mp4box.min.js"></script>
    <script>
      const imgBg = document.querySelector('.bg');
      /** @type {HTMLVideoElement} */
      const video = document.querySelector('.video');
      /** @type {HTMLCanvasElement} */
      const canvas = document.querySelector('.canvas');

      /** @type {CanvasRenderingContext2D} */
      const ctx = canvas.getContext('2d');

      const mp4box = MP4Box.createFile();
      // console.log("mp4box => ", mp4box)

      // 解码的视频轨道
      let videoTrack = null,
        videoDecoder = null;
      // 解码的视频画面序列文件
      const videoFrames = [];

      let nbSampleTotal = 0,
        countSample = 0;

      mp4box.onError = (e) => {
        console.error('Error:', e);
      };
      mp4box.onReady = (info) => {
        console.log('Info:', info);
        videoTrack = info.videoTracks[0];

        if (videoTrack) {
          // 提取给定 `track id` 的轨道样本
          mp4box.setExtractionOptions(videoTrack.id, 'video', {
            // 每次回调调用的样本数
            nbSamples: 100,
          });
        }

        // 设置视频解码器
        videoDecoder = new VideoDecoder({
          async output(videoFrame) {
            // console.log('videoFrame => ', videoFrame);

            const img = await createImageBitmap(videoFrame);
            videoFrames.push({
              img,
              duration: videoFrame.duration,
              timestamp: videoFrame.timestamp,
            });
            videoFrame.close();
          },
          error(err) {
            console.log('videoDecoder error => ', err);
          },
        });

        nbSampleTotal = videoTrack.nb_samples;

        videoDecoder.configure({
          codec: videoTrack.codec,
          codedWidth: videoTrack.track_width,
          codedHeight: videoTrack.track_height,
          description: getExtraData(),
        });

        mp4box.start();
      };
      mp4box.onSamples = (tranckId, ref, samples) => {
        // console.log('Samples:', tranckId, ref, samples);
        // samples 采集的数据
        if (videoTrack.id === tranckId) {
          mp4box.stop();

          countSample += samples.length;

          for (const { is_sync, duration, data, cts } of samples) {
            const type = is_sync ? 'key' : 'delta';

            const chunk = new EncodedVideoChunk({
              type,
              timestamp: cts,
              duration,
              data,
            });

            videoDecoder.decode(chunk);
          }

          if (countSample === nbSampleTotal) {
            videoDecoder.flush();
          }
        }
      };

      /**
       * 生成 `VideoDecoder`.configure() 参数的 `description` 信息
       */
      function getExtraData() {
        const entry = mp4box.moov.traks[0].mdia.minf.stbl.stsd.entries[0];

        const box = entry.avcC ?? entry.hvcC ?? entry.vpcC;
        if (box) {
          const stream = new DataStream(undefined, 0, DataStream.BIG_ENDIAN);

          box.write(stream);
          return new Uint8Array(stream.buffer.slice(8));
        }
      }

      let index = 0;
      /**
       * @param {DOMHighResTimeStamp} now
       * @param {VideoFrameCallbackMetadata} metadata
       */
      function drawFrame() {
        const { img, timestamp, duration } = videoFrames[index];
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        ctx.globalCompositeOperation = 'source-over';
        // 绘制背景
        ctx.drawImage(imgBg, 0, 0, canvas.width, canvas.height);

        // 使用 screen 混合模式
        ctx.globalCompositeOperation = 'screen';
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

        index++;

        if (index === videoFrames.length) {
          index = 0;
        }

        video.requestVideoFrameCallback(drawFrame);
      }

      fetch('./fire.mp4')
        .then((res) => res.arrayBuffer())
        .then((buffer) => {
          buffer.fileStart = 0;

          mp4box.appendBuffer(buffer);
          mp4box.flush();
        });

      video.addEventListener('loadedmetadata', () => {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;

        video.requestVideoFrameCallback(drawFrame);
      });
    </script>
  </body>
</html>

标签:canvas,const,videoTrack,mp4box,videoFrame,mix,webcodecs,video,blend
From: https://www.cnblogs.com/chlai/p/18175782

相关文章

  • Razavi - RF Microelectronics的笔记 - Current-Driven Passive Mixer
    Onpage367,whilediscussingaboutcurrent-drivenpassivemixer,thereisthissaying:theswitchesinFig.6.39(b)alsomixthebasebandwaveformswiththeLO,deliveringtheupconvertedvoltagestonodeA.Iamquiteconfusedonwheredoesthiswave......
  • LO Self Mixing
    Duetothenonlinearityof\(C_{GS1}\)and\(C_{GS2}\)arisingfromlargeLOamplitudes,\(V_P\)doeschangewithtimebutonlyattwicetheLOfrequency.Idon'tquiteunderstandwheredoesthis"twice"comefrom.ThenIcheckProbl......
  • C. Mixing Water
    https://codeforces.com/contest/1359/problem/C题意:给h和c两个数,并且操作顺序必须是hchchchch...对这些操作求和后除以操作次数得到均值,要求这个均值尽可能的接近t。问在最接近t的情况下,最少需要进行多少次操作。思路:如果(h+c)/2>=t,那么则只需两次操作最优。如果h==t,......
  • 【MMD x EEVEE教程】工具篇 • blender设置
    这篇教程适合有一定基础的萌新....*&blender下载官方网址https://www.blender.org/官方blender,都是最新版,如果需要找旧版的blender可以到这里来https://download.blender.org/release/,里边包好了所有版本的blender,因为是做MMD,下载自己需要版本后,建议额外下载一个2.93版的,某些时......
  • 解决报错:blocked:mixed-content
    问题发生背景:本来好好的官网,没有做任何改变时突然发现F12调用后端接口报错:blocked:mixed-content解决办法:1、直接点击网站设置 这样临时解决,但是也不能让使用者去设置,毕竟不是每个使用者都是用的chrome或者熟悉浏览器设置,此种解决办法pass。2、blocked:mixed-content报错原......
  • ue4.26 通过材质开关控制mesh pass的blend function
    一,meshpass中blendfunction的设置方法在meshpass中设置blendfunction有如下几种方式:1,在CreateXXXProcessor(返回FXXXProcessor)中: 2,FXXXProcessor::AddMeshBatch中: 3,FXXXProcessor::Process中: 4,RenderXXX中: 二,材质开关访问途径我们知道,访问材质开关有以下几种......
  • blender python api 将指定的顶点组(water)转换为颜色属性water_colors
    1.选中物体,进入权重绘制模式2.代码:importbpy#获取当前活动的物体obj=bpy.context.object#确保物体是网格类型ifobj.type!='MESH':print("当前激活的对象不是网格类型。")#exit()#使用exit()来提前退出脚本#获取名为“water”的顶点组vertex_gro......
  • blender python api 获取所有顶点组并将各自的顶点组转换为对应的颜色属性
    1.选中物体,进入权重绘制模式2.代码importbpy#获取当前活动的物体obj=bpy.context.object#确保物体是网格类型ifobj.type!='MESH':print("当前激活的对象不是网格类型。")#exit()#遍历所有顶点组forvg_nameinobj.vertex_groups.keys():#获......
  • blender python api 使用脚本进行动画渲染
    1.摄像机“Camera”在一个名叫“渲染”的集合中2.代码:importbpy#设置输出路径和文件名output_path="/path/to/output/"#替换为你的输出路径filename="rendered_animation"#输出文件的前缀#获取名为“渲染”的集合render_collection_name="渲染"render_c......
  • R语言建立和可视化混合效应模型mixed effect model|附代码数据
    全文下载链接:http://tecdat.cn/?p=20631最近我们被客户要求撰写关于混合效应模型的研究报告,包括一些图形和统计输出我们已经学习了如何处理混合效应模型。本文的重点是如何建立和_可视化_ 混合效应模型的结果设置本文使用数据集,用于探索草食动物种群对珊瑚覆盖的影响。 ......