为了账号安全,请及时绑定邮箱和手机立即绑定

一起从零开始手写一个动态视频截图工具吧

  我们可能经常看到这样的一个功能,在视频播放的过程中,动态的将视频中的某一帧截下来。

  或者一些更常见的比如视频首帧截图。那这样的一个功能,具体是怎样实现的?一起来做做吧。

  整体的方案大致是这样:首先需要准备几个子功能模块。首先,得有视频,能播视频,并且可以做到实时的监听视频的进度,其次就是截图了。核心功能有了,除此之外呢?既然是动态的,所以最好还要有一个动态的dom结构插入方便展示结果,还得能方便的更换视频,也就是视频上传,当然我们为了简单化,这里不涉及后台,但以上的功能同样都能实现。

  首先,可以播放视频,通过HTML5的video来实现,具体如何呢?

  下面是一个video标签,这样一个标签,就可以播放视频。

<video src="../assets/123.mp4" controls class='video'></video>

  video如何监听进度的呢?
  video的事件实际上非常多,这里就不一一列举了,我们看MDN,如下图:

图片描述
  可以看到这里面有一个事件是timeupdate,这就是我们想要的进度监听。


_self.video.addEventListener('timeupdate', function (e) {

    console.log('当下进度为: ' + this.currentTime);
    console.log('视频总时长为: ' + this.duration);
});

  其次,处理截图,处理图片比如对图片做压缩做剪切做各种各样的处理,日常的软件其实就是类似photoshop这样的图片软件,或者更加原始的就是通过画图软件,但程序怎么做呢?画图画图,可能这时候你也意识到了,没有错,基本都可以通过HTML5的画布(canvas)来实现。看一段下面的代码。


//  创建画布
    createCanvas () {

        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        
        this.canvas = canvas;
        this.ctx = ctx;
    }

这时候再配合一下刚刚的timeupdate进度监听,就可以基本实现我们的核心功能了。


var nowTime = 0;

_self.video.addEventListener('timeupdate', function (e) {

    if(this.currentTime > nowTime){

        _self.ctx.drawImage(this, 0, 0, this.videoWidth, this.videoHeight);

        let src = _self.canvas.toDataURL('image/jpeg');

        _self.appendImg(src);
        
        nowTime += _self.speed;
    }
});

  但这时候你会发现,截出来的图不对,好像只截了一部分,这时候就需要设置一下画布的大小了。但因为传入不同的视频,呈现的画面大小其实都是不一致的,所以需要根据视频上传后或者加载后的第一帧,取这时候的video大小。

  这时候video也同样提供一个当video加载完视频文件的第一帧时的事件。即loadeddata。看看:


_self.video.addEventListener('loadeddata', function () {

    _self.canvas.width = this.videoWidth;
    _self.canvas.height = this.videoHeight;
});

  这样我们基本上就完成了核心的功能。

  接下来,再附上一个视频上传的功能,这时候dom结构稍微做一下变动,这其实就是一个典型的隐式表单提交。


<div class='container'>
    <div class='video-container'>
        <input type="file" id="input" hidden />
        <video src="../assets/123.mp4" controls class='video'></video>
        <button>上传视频</button>
    </div>
    <div class='screenshot-list screenshotList'></div>
</div>

//  video文件上传
upLoadFile () {

    let _self = this;

    _self.input.addEventListener('change', function (e) {

        _self.file = this.files[0];
        _self.src = window.URL.createObjectURL(_self.file);

        _self.video.src = _self.src;
    });

    _self.btn.addEventListener('click', function () {

        _self.input.click();
    });
}

  当然,动态截取出来的图片需要让我们的感官有直观的体验,当然是将之动态的展现出来。当然加点Css3的动画效果就更好了。


appendImg (src) {

    var screenshotList = document.querySelector('.screenshotList');

    var oDiv = document.createElement('div'),
        img = document.createElement('img');
        img.src = src;

    oDiv.className = 'pd10 animated bounceInRight';
    oDiv.appendChild(img);

    screenshotList.insertBefore(oDiv, screenshotList.querySelector('div'));

    // screenshotList.appendChild(oDiv);
    // screenshotList.scrollTop = screenshotList.scrollHeight;
}

  这样基本就完成了我们的功能了。

  看一看总体的代码:


class videoCapture {

    constructor (options) {

        this.Dom = options.Dom;

        this.speed = options.speed || 2;

        this.input = this.Dom.querySelector('input');
        this.btn = this.Dom.querySelector('button');
        this.video = this.Dom.querySelector('video');
        this.image = this.Dom.querySelector('img');

        this.file = '';
        this.src = '';

        this.initEvent();
    }

    //  video文件上传
    upLoadFile () {

        let _self = this;

        _self.input.addEventListener('change', function (e) {

            _self.file = this.files[0];
            _self.src = window.URL.createObjectURL(_self.file);

            _self.video.src = _self.src;
        });

        _self.btn.addEventListener('click', function () {

            _self.input.click();
        });
    }
    //  创建画布
    createCanvas () {

        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        
        this.canvas = canvas;
        this.ctx = ctx;
    }
    initEvent () {

        let _self = this;

        _self.upLoadFile();
        _self.createCanvas();
        
        _self.video.addEventListener('loadeddata', function () {

            _self.canvas.width = this.videoWidth;
            _self.canvas.height = this.videoHeight;
        });

        var nowTime = 0;

        _self.video.addEventListener('timeupdate', function (e) {

            if(this.currentTime > nowTime){

                _self.ctx.drawImage(this, 0, 0, this.videoWidth, this.videoHeight);

                let src = _self.canvas.toDataURL('image/jpeg');

                _self.appendImg(src);
                
                nowTime += _self.speed;
            }
        });
    }
    appendImg (src) {

        var screenshotList = document.querySelector('.screenshotList');

        var oDiv = document.createElement('div'),
            img = document.createElement('img');
            img.src = src;

        oDiv.className = 'pd10 animated bounceInRight';
        oDiv.appendChild(img);

        screenshotList.insertBefore(oDiv, screenshotList.querySelector('div'));

        // screenshotList.appendChild(oDiv);
        // screenshotList.scrollTop = screenshotList.scrollHeight;
    }
}
export default videoCapture;

  再看一看调用:


layout: false
title: "视频动态截图"
date: 2019-09-19 20:03:48
---
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="../css/animate.css">
    <link rel="stylesheet" href="../css/dynamicScreenshots.css">
    <title>视频动态截图</title>
</head>
<body>
    <div class='container'>
        <div class='video-container'>
            <input type="file" id="input" hidden />
            <video src="../assets/123.mp4" controls class='video'></video>
            <button>上传视频</button>
        </div>
        <div class='screenshot-list screenshotList'></div>
    </div>
    <script type='module'>

        import videoCapture from '../js/dynamicScreenshots/dynamicScreenshots.js';

        let Dom = document.querySelector('.container'),
            speed = 2;

        new videoCapture({ Dom, speed });
        
    </script>
</body>
</html>

最后呢,当然是上效果了。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
1.3万
获赞与收藏
1519

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消