5

On my page, I have a looping video playing. When hitting Play, another video is masked on top of that and it slowly appears. In short, I am masking a video with another video (black/white mask turned into alphadata by Canvas)

The tutorial is adapted from here

This works, but the transition/video are incredible slow because canvas is looping through all the pixels. Does anyone have any pointers on another way to accomplish this or speed up the process?

A working demo of this code can be found here

HTML:

//Buffer canvas (stacked video's: result + alpha mask)
<canvas style="display:none" width="1920" height="2160" id="buffer">     
</canvas>

//Output canvas (combines mask with video)
<canvas class="video__output " width="1920" height="1080" id="output">
</canvas> 

//buffer canvas uses this video to extract data
<video class="" id="video" preload="auto" style="display:none" >
    <source src="assets/video/masking.mp4" type='video/mp4;codecs="avc1.42E01E"' />
</video>


//Video loop always playing
<video poster="assets/video/poster_desktop.jpg" class="video--top loop" autoplay loop>
    <source src="assets/video/loop.mp4"  type='video/mp4; codecs="avc1.42E01E"' />
</video> 

JS:

function processFrame() {
    buffer.drawImage(video, 0, 0);

    //Get alphadata
    let image = buffer.getImageData(0, 0, width, height),
    imageData = image.data,
    alphaData = buffer.getImageData(0, height, width, height).data;

    //Loop through pixels, replace data with alpha channel
    for (let i = 3, len = imageData.length; i < len; i = i + 4) {
        imageData[i] = alphaData[i-1];
    }

    //Output to second canvas
    output.putImageData(image, 0, 0, 0, 0, width, height);
    requestAnimationFrame(processFrame)
}
Nike Sprite
  • 476
  • 2
  • 16
  • *Speed up the process significantly?* Probably not ... `getImageData` is just slow. Doing it simultanteously on 2 videos is slooooooow! For better performance you will need to pre-process at least the masking video and possibly both videos. – markE Mar 09 '16 at 05:50
  • Also, one way to significantly improve speed when manipulating video pixels is to lower the quality of the video. First draw it smaller, process the transparency thing and save it somewhere (a second canvas may be needed) Redraw the full-sized video frame, set the `globalCompositeOperation` to `"source-in"`, and finally redraw the small transparent one at original scale. Here you've got a full quality video, with some rugged edges on the border of the alpha mask, but it shouldn't matter too much for videos. [See this post.](http://stackoverflow.com/questions/33687775/33727707#33727707) – Kaiido Mar 09 '16 at 11:07
  • Why don't you simply cross-fade your two video elements? – Roko C. Buljan Apr 04 '16 at 05:30

1 Answers1

0

Option one is to reduce the two getImageData()s to a single call. Get the complete bitmap, then use two pointers instead, one pointing to the RGB data and the second to the start of the matte data.

Option two is to consider using the webm video format. This has support for alpha channel BUT is currently only supported in the Chrome browser (and newer Opera I think).