Write the Code. Change the World.

1月 10

前端 html 页面中,选择上传视频文件,获取视频文件的长度以及截取封面是个很常见的功能。前端 js 也能实现这个功能。

流程: file -> loadedmetadata(获取视频元信息)->currentTime(定格到视频的位置)->绘制到 canvas->转换成图片

  1. 通过 input(file) 选择文件。
    https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input/file

    <div>
    <label class="upload-btn" for="video">
        <span class="text">上传</span>
    </label>
    <input class="hidden" id="video" name="video" type="file" accept="video/mp4" @change="changeVideo" />
    </div>
  2. 获取视频元信息。
    https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/video

使用 createObjectURL 创建的URL是一个blob:开头的临时路径,这个路径可以在浏览器中直接访问,访问到的内容就是上传的视频文件。当页面关闭后,此路径也随之失效。

function changeVideo() {
    const fileInput: HTMLInputElement = document.getElementById('video') as HTMLInputElement
    const files: FileList = fileInput?.files as FileList
    const file = files[0]

    const video = document.createElement('video')
    video.src = URL.createObjectURL(file)
    video.addEventListener('loadedmetadata', function () {
        console.log(video.duration)
    })
}
  1. 定格到视频位置

    // 设置视频自动播放
    video.autoplay = true
    // 设置视频播放的时间(方便截图)
    video.currentTime = 1
  2. 绘制 canvas

    const canvas = document.createElement("canvas");
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    const ctx = canvas.getContext("2d");
    if (ctx) {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    // document.body.appendChild(canvas);
    }
  3. 将 canvas 转换成图片

    canvas.toBlob((blob) => {
    if (blob) {
    const url = URL.createObjectURL(blob);
    }
    });

完整的 ts。


interface VideoInfo {
    name: string
    width: number
    height: number
    thumbnail?: string
    duration?: number
}

function getVideoInfo(file: File, maxWidth = 320) {
    return new Promise<VideoInfo>((resolve) => {
        const index = file.name.lastIndexOf('.')
        const name = index > 0 ? file.name.substring(0, index) : ''
        const videoMedia: VideoInfo = {
            name,
            width: 0,
            height: 0
        }

        const video = document.createElement('video')
        video.src = URL.createObjectURL(file)
        video.addEventListener('loadedmetadata', function () {
            videoMedia.width = video.videoWidth
            videoMedia.height = video.videoHeight
            videoMedia.duration = video.duration
        })

        // 监听视频跳转完成事件
        video.addEventListener('seeked', function () {
            // 创建画布并绘制视频帧
            const canvas = document.createElement('canvas')
            const ctx = canvas.getContext('2d')

            if (video.videoWidth > maxWidth) {
                canvas.width = maxWidth
                canvas.height = Math.round((maxWidth / video.videoWidth) * this.videoHeight)
            } else {
                canvas.width = video.videoWidth
                canvas.height = video.videoHeight
            }

            if (ctx) {
                ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
                canvas.toBlob((blob) => {
                    if (blob) {
                        videoMedia.thumbnail = URL.createObjectURL(blob)
                        resolve(videoMedia)
                    } else {
                        resolve(videoMedia)
                    }
                })
            } else {
                resolve(videoMedia)
            }
            // 释放创建的临时URL
            // URL.revokeObjectURL(video.src)
        })

        // 设置视频自动播放
        video.autoplay = true
        // 设置视频播放的时间(方便截图)
        video.currentTime = 1
    })
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注