优化两个画布中播放的两个视频的播放效果

时间:2018-05-03 20:08:04

标签: canvas optimization

我有一对正在画布里面播放的剪辑。偶尔我只看到视频的黑色,未剪辑和未渲染,页面必须刷新。有没有人知道为什么会这样?

它似乎正在工作但我也可以听到视频卡有时会慢慢变大。你觉得它会以某种方式减慢requestAnimationFrame功能吗?这一切都是非常实验性的,我可以用一双额外的眼睛来做。

这是我的源代码,并提前感谢您。

function makeLeftCanvasPath(ctx, width, height, widthFifteenPercent) {
  ctx.beginPath();
  ctx.moveTo(0, 0);
  ctx.lineTo(width, 0);
  ctx.lineTo(width - widthFifteenPercent, height);
  ctx.lineTo(0, height);
  ctx.lineTo(0, 0);
  ctx.closePath();
}

function makeRightCanvasPath(ctx, width, height, widthFifteenPercent) {
  ctx.beginPath();
  ctx.moveTo(widthFifteenPercent, 0);
  ctx.lineTo(width, 0);
  ctx.lineTo(width, height);
  ctx.lineTo(0, height);
  ctx.lineTo(widthFifteenPercent, 0);
  ctx.closePath();
}

var VideoSplit = function(container, sourceA, sourceB) {
  var leftMediaSource = sourceA;
  var leftMuted = true;

  var leftCanvas = document.createElement('canvas');
  leftCanvas.id = 'leftCanvas';

  var ctxLeft = leftCanvas.getContext("2d");
  var leftVideoContainer;
  var leftVideo = document.createElement("video");

  leftVideo.src = leftMediaSource;
  leftVideo.autoplay = false;
  leftVideo.loop = true;
  leftVideo.muted = leftMuted;

  leftVideoContainer = {
    leftVideo: leftVideo,
    ready: false,
    ctx: ctxLeft
  };

  leftVideo.oncanplay = readyToPlayVideoLeft;

  var rightMediaSource = sourceB;
  var rightMuted = true;

  var rightCanvas = document.createElement('canvas');

  rightCanvas.id = 'rightCanvas';

  var ctxRight = rightCanvas.getContext("2d");
  var rightVideoContainer;
  var rightVideo = document.createElement("video");

  rightVideo.src = rightMediaSource;
  rightVideo.autoplay = false;
  rightVideo.loop = true;
  rightVideo.muted = rightMuted;

  $(rightVideo).attr('playsinline', '');

  rightVideoContainer = {
    leftVideo: rightVideo,
    ready: false,
    ctx: ctxRight
  };



  rightVideo.oncanplay = readyToPlayVideoRight;


  // Create an overlay to capture mouse events
  var eventOverlay = document.createElement('div');
  eventOverlay.classList.add('eventOverlay');


  container.appendChild(leftCanvas);
  container.appendChild(rightCanvas);
  container.appendChild(eventOverlay);


  // Syncronise dimensions:
  leftCanvas.width = leftCanvas.clientWidth;
  rightCanvas.width = rightCanvas.clientWidth;

  leftCanvas.height = leftCanvas.clientHeight;
  rightCanvas.height = rightCanvas.clientHeight;

  syncroniseCoordinateSystems();
  ctxLeft.save();
  ctxRight.save();




  function syncroniseCoordinateSystems() {
    // Syncronise dimensions:
    var containerWidth = window.getComputedStyle(container).width;


    container.style.height = (parseInt(containerWidth) / 100 * 56.25) / 2 + 'px';
    var height = parseInt(container.style.height);

    // Get 54.5% of the container width

    var percentageOfWidth = parseInt(containerWidth) / 100 * 54.5;

    leftCanvas.width = percentageOfWidth;
    rightCanvas.width = percentageOfWidth;

    leftCanvas.height = height;
    rightCanvas.height = height;

    leftCanvas.style.height = leftCanvas.height + 'px';
    rightCanvas.style.height = rightCanvas.height + 'px';


    var fifteenPercentOfWidth = rightCanvas.width / 100 * 15;
    makeLeftCanvasPath(ctxLeft, leftCanvas.width, leftCanvas.height, fifteenPercentOfWidth);
    ctxLeft.clip();

    makeRightCanvasPath(ctxRight, ctxRight.canvas.width, ctxRight.canvas.height, fifteenPercentOfWidth);
    ctxRight.clip();


  }

  function readyToPlayVideoRight(event) {
    rightVideoContainer.ready = true;
  }

  function readyToPlayVideoLeft(event) {
    leftVideoContainer.ready = true;
    requestAnimationFrame(updateCanvasLeft);
  }

  function updateCanvasLeft() {

    var containerWidth = window.getComputedStyle(container).width;

    // Set the style of the actual container so it retains video aspect ratio
    container.style.height = (parseFloat(containerWidth) / 100 * 56.25) / 2 + 'px';

    var height = parseFloat(container.style.height);
    var width = parseInt(containerWidth) / 100 * 54.5;


    // only draw if loaded and ready
    if (leftVideoContainer !== undefined && leftVideoContainer.ready && rightVideoContainer !== undefined && rightVideoContainer.ready) {
      ctxLeft.drawImage(leftVideoContainer.leftVideo, 0, 0, width, height);
      ctxRight.drawImage(rightVideoContainer.leftVideo, 0, 0, width, height);
    }

    requestAnimationFrame(updateCanvasLeft);
  }




  window.addEventListener('resize', function() {
    syncroniseCoordinateSystems();

    var fifteenPercentOfWidth = leftCanvas.width / 100 * 15;

    makeLeftCanvasPath(ctxLeft, leftCanvas.width, leftCanvas.height, fifteenPercentOfWidth);
    ctxLeft.clip();
    makeRightCanvasPath(ctxRight, ctxRight.canvas.width, ctxRight.canvas.height, fifteenPercentOfWidth);
    ctxRight.clip();
  });




  function playPauseClick(canvasClicked) {
    var canvasClickedId = canvasClicked.id;
    var videoContainer = (canvasClickedId == 'leftCanvas' ? leftVideoContainer : rightVideoContainer);

    if (videoContainer !== undefined && videoContainer.ready) {
      if (videoContainer.leftVideo.paused) {
        videoContainer.leftVideo.play();
      }
    }
  }

  eventOverlay.addEventListener('mousemove', function(e) {
    var rect = this.getBoundingClientRect();
    var x = e.clientX - rect.left;
    var y = e.clientY - rect.top;

    if (ctxLeft.isPointInPath(x, y)) {
      leftVideo.play();
      rightVideo.pause();
    } else {
      leftVideo.pause();
      rightVideo.play();
    }
  });

  eventOverlay.addEventListener('mouseout', function(e) {
    leftVideo.pause();
    rightVideo.pause();
  });

};

1 个答案:

答案 0 :(得分:0)

您可以在单个画布上绘制所有内容,只使用一个路径,而不是clip()

通过使用多个compositing operations,您可以获得与裁剪相同的结果:

  • 首先以正常模式source-over填充您的路径。
  • 然后以source-in模式绘制您的第一个视频,这样只有那些与已经存在的像素重叠的像素(即在您的路径上)才会保留。
  • 最后以destination-over模式绘制您的第二个视频,这将在后面现有像素。

VideoSplit(
  document.getElementById('container'),
  'https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm',
  'https://upload.wikimedia.org/wikipedia/commons/a/a4/BBH_gravitational_lensing_of_gw150914.webm'
);

function VideoSplit(container, sourceA, sourceB) {
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');

  var video1 = loadVid(sourceA);
  var video2 = loadVid(sourceB);

  var width, height, long_width, short_width;

  var shouldResize = false,
    paused = false,
    canvas_rect = null;

  var loaded = 0;

  window.addEventListener('resize', function() {
    if(paused && !shouldResize) requestAnimationFrame(draw);
    shouldResize = true;
  });
  canvas.addEventListener('mousemove', toggleVid);
  canvas.addEventListener('mouseout', pauseVids);


  function init() {
    container.appendChild(canvas);
    resize();
    draw();
    pauseVids();
  }

  function resize() {
    var cont_rect = container.getBoundingClientRect();
    width = canvas.width = cont_rect.width;
    height = canvas.height = (cont_rect.width / 2) * 0.5625; // 16/9 ratio
    container.style.height = height + 'px';

    // since we are dealing with a single path, we can draw it only when resizing the canvas
    drawPath();
    // save our canvas bounding rect so we don't have to request it anymore
    canvas_rect = canvas.getBoundingClientRect();
    shouldResize = false;
  }

  function drawPath() {
    var w = width / 2,
      margin = w * (0.15 / 2);
    ctx.beginPath();
    ctx.lineTo(0, 0);
    ctx.lineTo(w + margin, 0); // 7.5% on the right of the center
    ctx.lineTo(w - margin, canvas.height); // 7.5 % on the left of the center
    ctx.lineTo(0, canvas.height);
  }

  function draw() {
    if (shouldResize) {
      // resize only in the rAF callback, so it fires once per frame at max
      resize();
    } else {
      if (paused) return; // force redraw on resize, even if paused
      // micro-optimization... resizing already clears the canvas
      ctx.globalCompositeOperation = 'source-over';
      ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    }
    var w = width / 2,
      margin = w * (0.15 / 2);

    ctx.fill(); // draws our Path
    ctx.globalCompositeOperation = 'source-in'; // next drawing will occur only on the drawn Path
    ctx.drawImage(video1, 0, 0, w + margin, height);
    ctx.globalCompositeOperation = 'destination-over'; // next drawing will occur behind current drawing
    ctx.drawImage(video2, w - margin, 0, w + margin, height);

    requestAnimationFrame(draw); // do it again
  }

  function toggleVid(evt) {
    var mouse_x = evt.clientX - canvas_rect.left;
    var mouse_y = evt.clientY - canvas_rect.top;
    if (ctx.isPointInPath(mouse_x, mouse_y)) {
      video1.play();
      video2.pause();
    } else {
      video2.play();
      video1.pause();
    }
    if (paused) {
      paused = false;
      draw();
    }
  }

  function pauseVids() {
    video1.pause();
    video2.pause();
    paused = true;
  }

  function onVidload() {
    if (++loaded === 2)
      init();
  }

  function loadVid(url) {
    var video = document.createElement('video');
    video.src = url;
    video.onloadedmetadata = onVidload;
    video.onerror = function() {
      console.error('failed to load video resource, check you are on a browser that does support webm video format')
    };
    video.muted = true;
    video.repeat = true;
    video.play();
    return video;
  }
}
<div id="container"></div>
<p>mouse over the canvas to toggle the video's playing</p>