audio、video、canvas、截取视频设置封面、截取某个时间画面、根据鼠标实时更新视频封面

3,300 阅读3分钟

效果:





要点:

  • 音频:<audio src='' controls="controls""></audio>

  • 视频:<video id='video' src='' crossOrigin="anonymous" controls="controls"></video>

  • react视频组件:

    import { Player } from 'video-react';
    import '../../../node_modules/video-react/dist/video-react.css'
    ...
    <Player ref="player" videoId="video-1" className="video_d">
        <source src=''  />
    </Player>
  • 设置视频加载到的时间长度:

    const video = document.getElementById('video')
    video.currentTime = 5//设置视频当前时长
  • 获取视频总时长:

    const video = document.getElementById('video')
    video.duration//获取视频总时长
  • canvas.toDataURL('image/png')如果该方法提示画布受污染,则在video标签加上crossOrigin="anonymous"属性

  • loadeddata:提示当前帧的数据是可用的;当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时,会发生 loadeddata 事件。

    video.addEventListener('loadeddata',()=>{});

示例:

video.js:

import React, { Component } from 'react'
import { Player } from 'video-react';
import '../../../node_modules/video-react/dist/video-react.css'
import './video.less'

export default class Video extends Component {
    constructor(props) {
        super(props)
        this.state = {
            inputVideoUrl: 'http://wvideo.spriteapp.cn/video/2016/0328/56f8ec01d9bfe_wpd.mp4',
            audioUrl: 'http://www.170mv.com/kw/antiserver.kuwo.cn/anti.s?rid=MUSIC_53912340&response=res&format=mp3|aac&type=convert_url&br=128kmp3&agent=iPhone&callback=getlink&jpcallback=getlink.mp3',

            video_duration: '',//视频总时长
            time_d: 0,//视频当前时长
        }
    }
    componentDidMount() {
        const video = document.getElementById('video')
        video.currentTime = 5//设置视频当前时长

        // loadeddata:提示当前帧的数据是可用的        // 当当前帧的数据已加载,但没有足够的数据来播放指定音频/视频的下一帧时,会发生 loadeddata 事件。        video.addEventListener('loadeddata', ()=>{            this.captureImage()            this.setState({                video_duration: video.duration//获取视频总时长            }, () => {                this.mouseMoveFun()            })        });
    }
    // 自动截取视频第一帧作为封面
    captureImage() {
        const video = document.getElementById('video')
        const preview = document.getElementById('preview')

        const canvas = document.createElement('canvas')                            //创建一个canvas
        canvas.width = video.offsetWidth
        canvas.height = video.offsetHeight

        canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)//绘制图像
        const img = new Image()                                                    //创建img
        img.src = canvas.toDataURL('image/png')                                    //将绘制的图像用img显示
        preview.appendChild(img)
    }
    // 手动截取视频画面作为封面
    buttonFun() {
        const canvas = document.getElementById('canvas')
        const video = document.getElementById('video')

        let context = canvas.getContext('2d');
        context.clearRect(0, 0, 400, 200);                                         //清除画布内容
        context.drawImage(video, 0, 0, 400, 200);
    }
    // 监听鼠标在容器内的位置
    mouseMoveFun() {
        let { video_duration } = this.state
        let _this = this
        const preview = document.getElementById('preview')
        const scrllo_val = document.getElementById('scrllo_val')

        preview.onmousemove = function (event) {
            event = event || window.event;
            //2.获取鼠标在整个页面的位置  
            let pagex = event.pageX;
            let pagey = event.pageY;
            //3.获取盒子在整个页面的位置  
            let xx = preview.offsetLeft;
            let yy = preview.offsetTop
            //4.用鼠标的位置减去盒子的位置赋值给盒子的内容。  
            let targetx = pagex - xx;
            let targety = pagey - yy;
            // this.innerHTML = "鼠标在盒子中的X坐标为:" + targetx + "px;<br>鼠标在盒子中的Y坐标为:" + targety + "px;"

            let preview_width = preview.offsetWidth
            let time = targetx / preview_width
            let time_d = time * video_duration//鼠标当前时长

            let scrllo_val_wid = preview_width * time
            scrllo_val.style.width = scrllo_val_wid + 'px'//实时更新进度条


            _this.setState({
                time_d
            }, () => {
                // console.log(time_d)
                if (Number(time_d.toFixed(0)) % 20 == 0) {//避免密集截屏导致卡顿
                    _this.previewFun()
                }
            })
        }
    }
    // 鼠标视频实时预览
    previewFun() {
        let { time_d } = this.state
        const canvas = document.createElement('canvas')
        const video = document.getElementById('video')
        const preview = document.getElementById('preview')

        video.currentTime = time_d//设置视频当前时长

        let context = canvas.getContext('2d');
        context.clearRect(0, 0, 400, 200);                                         //清除画布内容
        context.drawImage(video, 0, 0, 400, 200);

        const img = new Image()                                                    //创建img
        img.src = canvas.toDataURL('image/png')                                    //将绘制的图像用img显示

        let childImg = preview.childNodes;
        if (childImg.length > 1) {
            preview.removeChild(childImg[1])//清除已有img
        }

        preview.appendChild(img)
    }
    render() {
        return (
            <div className='video_main'>
                <div className='title'>音频播放--audio</div>
                <audio src={this.state.audioUrl} controls="controls" className="audio_d">
                    您的浏览器不支持 audio 标签。
                </audio>

                <div className='title'>视频播放--Player</div>
                <Player ref="player" videoId="video-1" className="video_d">
                    <source src={this.state.inputVideoUrl}  />
                </Player>

                <div className='title'>视频播放--video</div>
                <div id='video_div'>
                    <video id='video' src={this.state.inputVideoUrl} crossOrigin="anonymous" controls="controls" className="video_d">
                        您的浏览器不支持 video 标签。
                </video>
                </div>


                <button onClick={this.buttonFun.bind(this)} style={{ margin: '20px' }}>截取视频</button>

                <div className='title'>截取视频--canvas</div>
                <div className='canvas'>
                    <canvas id="canvas" width="400" height="200"></canvas>
                </div>

                <div className='title'>视频预览</div>
                <div id='preview'>
                    <div className='scrllo_bg'>
                        <div id='scrllo_val'></div>
                    </div>
                </div>

            </div>
        )
    }
}

video.less:

.video_main{
    width: 100%;
    height: 100vh;
    overflow: auto;
    .title{
        font-size: 24px;
        margin: 20px;
    }
    .video_d{
        height: 200px;
        width: 400px;
        padding: 0px!important;
        position: relative;
        margin: auto;
        .video-react-big-play-button{
            position: absolute;
            left: 50%;
            margin-left: -43px;
            top: 50%;
            margin-top: -22.5px;
        }
    }
    .audio_d{
        width: 400px;
    }

    .canvas{
        width: 400px;
        height: 200px;
        border: 1px solid red;
        margin: auto;
    }
    #output{
        width: 400px;
        height: 200px;
        border: 1px solid red;
    }
    #preview{
        width: 400px;
        height: 200px;
        border: 1px solid red;
        position: relative;
        cursor: pointer;
        margin: auto;
        img{
            width: 100%;
            height: 100%;
        }
        .scrllo_bg{
            height: 5px;
            width: 100%;
            background: gray;
            position: absolute;
            top: 10px;
            opacity: 0;
            #scrllo_val{
                background: #fff;
                height: 100%;
            }
        }
    }
    #preview:hover{
        .scrllo_bg{
            opacity: 1;
        }
    }
}