Front-end ffmpeg compressed video

Download ffmpeg

npm install @ffmpeg/core @ffmpeg/ffmpeg

Here you need to pay attention to the versions of the two plug-ins: "@ffmpeg/core": "^0.10.0", "@ffmpeg/ffmpeg": "^0.10.1"

Configure ffmpeg

After installing the plug-in, you need to configure the code, otherwise an error will be reported:

1. Taking VUE as an example, configure the request header in the vue.config.js file

devServer: {
	headers: {
		'Cross-Origin-Opener-Policy': 'same-origin',
		'Cross-Origin-Embedder-Policy': 'require-corp'
	}
}

2. When instantiating ffmpeg on the page, an error that the module cannot be found may be reported.

const ffmpeg = createFFmpeg({
      // ffmpeg路径
      corePath: 'ffmpeg-core.js',
      // 日志
      log: true,
      // 进度
      progress: ({ ratio }) => {
           _this.msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`
      }
})

Therefore, it is best to put the downloaded plug-in file in the public folder.

 Use ffmpeg to compress video

  • Introduce ffmpeg
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
  •  File upload Get uploaded files
<input id="upload" type="file" accept="video/mp4" capture="camcorder" @change="upload">

Note: capture="camcorder" means obtaining the camera video of the mobile phone   View it yourself

  • Instantiate ffmpeg
// 实例化ffmpeg
const ffmpeg = createFFmpeg({
      // ffmpeg路径
      corePath: 'ffmpeg-core.js',
      // 日志
      log: true,
      // 进度
      progress: ({ ratio }) => {
          _this.msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`
      }
})
  • Compress video
await ffmpeg.load()
this.msg = '开始压缩'
// 把文件加到ffmpeg   写文件
ffmpeg.FS('writeFile', name, await fetchFile(file))
// await ffmpeg.run('-i', name, '-b', '2000000', '-fs', '4194304', '-preset medium', 'superfast', 'put.mp4')
// 开始压缩视频
await ffmpeg.run('-i', name, '-b', '2000000', '-crf', '23', '-fs', '4194304', '-s', resolution, 'put.mp4')
this.msg = '压缩完成'
// 压缩所完成,   读文件  压缩后的文件名称为 put.mp4
const data = ffmpeg.FS('readFile', 'put.mp4')

 Explanation of terms: -b: bit rate (that is, speed) -crf: compressed video quality -fs: compress the video to the specified size (it may be compressed to the specified size, but video clips after the specified size may be cut and delete the excess part) -preset medium: compression speed -s: resolution (can be used to specify the resolution of the video. The larger the resolution, the slower the compression time. The smaller the resolution, the faster the time). put.mp4: file name after compression is completed.

  • The compressed video format is blob format. The video format can be converted to file format as needed. The code is as follows:
// 类型转换 blob 转换 file
transToFile (data) {
    console.log(data)
    const _this = this
    var file = []
    // 转换bolb类型
    const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
    // 这么写是因为文件转换是异步任务
    const transToFile = async (blob, fileName, fileType) => {
        return new window.File([blob], fileName, { type: fileType })
    }
    const textContain = transToFile(blob, 'put.mp4', 'video/mp4')
    // 转换完成后可以将file对象传给接口
    textContain.then((res) => {
        file.push(res)
        console.log('res', res)
    })
    return file
},
  • If you think the compression time is too long, you can control the resolution of the video. The code is as follows:
getVideoData () {
    return new Promise((resolve, reject) => {
        const videoElement = document.getElementById('video')
        videoElement.addEventListener('loadedmetadata', function () {
            resolve({
                width: this.videoWidth,
                height: this.videoHeight,
                duration: this.duration
            })
        })
    })
},

Get the width and height of the video and scale it proportionally when compressing

There is a pitfall worth noting here: if the video is not loaded on the page, the width and height of the video will not be triggered. You need to load the video first. The code is as follows:

getObjectURL (file) {
    let url = null
    window.URL = window.URL || window.webkitURL
    if (window.URL) {
        url = window.URL.createObjectURL(file)
    } else {
        url = URL.createObjectURL(file)
    }
    return url
}

Give all the code

<template>
    <div class="video-box">
      <video id="video" controls object-fill="fill"></video><br />
      <input id="upload" type="file" accept="video/mp4" capture="camcorder" @change="upload">
    </div>
</template>

<script>
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
export default {
    data () {
        return {
            msg: '',
            videoWidth: '',
            videoHeight: '',
            duration: ''
        }
    },
    methods: {
        // 选择文件
        async upload (e) {
            console.log('start', e)
            console.log('start', e.target.files[0])
            var _this = this
            if (e.target.files[0]) {
                var filename = e.target.files[0].name
                var filetype = e.target.files[0].type

                const videoUrl = _this.getObjectURL(e.target.files[0])
                const video = document.getElementById('video')
                video.src = videoUrl

                this.getVideoData().then((videoObj) => {
                    const file = e.target.files[0]
                    console.log('videoObj:', videoObj)
                    const { width, height } = videoObj
                    const result = _this.squeezVideo(file, filename, filetype, width, height, _this.msg)
                    result.then(res => {
                        console.log('resultFile', res)
                    })
                })
            }
        },
        // 压缩视频
        async squeezVideo (file, filename, filetype, width, height) {
            console.log('squeezingVideo file name:  ', file.name)
            console.log('squeezingVideo file type:  ', file.type)
            console.log('squeezingVideo file path:  ', file.path)
            console.log('squeezingVideo file size:  ', file.size)
            console.log('squeezingVideo file lastModified:  ', file.lastModified)
            console.log('squeezingVideo file lastModifiedDate:  ', file.lastModifiedDate)
            const _this = this
            // 分辨率
            const resolution = `${width / 2}x${height / 2}`
            // 实例化ffmpeg
            const ffmpeg = createFFmpeg({
                // ffmpeg路径
                corePath: 'ffmpeg-core.js',
                // 日志
                log: true,
                // 进度
                progress: ({ ratio }) => {
                    _this.msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`
                }
            })
            var { name } = file
            this.msg = '正在加载 ffmpeg-core.js'
            // 开始加载
            await ffmpeg.load()
            this.msg = '开始压缩'
            // 把文件加到ffmpeg   写文件
            ffmpeg.FS('writeFile', name, await fetchFile(file))
            // await ffmpeg.run('-i', name, '-b', '2000000', '-fs', '4194304', '-preset medium', 'superfast', 'put.mp4')
            // 开始压缩视频
            await ffmpeg.run('-i', name, '-b', '2000000', '-crf', '23', '-fs', '4194304', '-s', resolution, 'put.mp4')
            this.msg = '压缩完成'
            // 压缩所完成,   读文件  压缩后的文件名称为 put.mp4
            const data = ffmpeg.FS('readFile', 'put.mp4')
            // 转换压缩后的视频格式  当前为 blob 格式
            var filed = _this.transToFile(data)
            console.log('transToFile: ', filed)
            return new Promise((resolve, reject) => {
                if (filed) {
                    resolve({
                        squzingFile: filed
                    })
                }
            })
        },
        // 获取视频的宽高分辨率
        getVideoData () {
            return new Promise((resolve, reject) => {
                const videoElement = document.getElementById('video')
                videoElement.addEventListener('loadedmetadata', function () {
                    resolve({
                        width: this.videoWidth,
                        height: this.videoHeight,
                        duration: this.duration
                    })
                })
            })
        },
        // 获取上传视频的url
        getObjectURL (file) {
            let url = null
            window.URL = window.URL || window.webkitURL
            if (window.URL) {
                url = window.URL.createObjectURL(file)
            } else {
                url = URL.createObjectURL(file)
            }
            return url
        },
        // 类型转换 blob 转换 file
        transToFile (data) {
            console.log(data)
            const _this = this
            var file = []
            // 转换bolb类型
            const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
            // 这么写是因为文件转换是异步任务
            const transToFile = async (blob, fileName, fileType) => {
                return new window.File([blob], fileName, { type: fileType })
            }
            const textContain = transToFile(blob, 'put.mp4', 'video/mp4')
            // 转换完成后可以将file对象传给接口
            textContain.then((res) => {
                file.push(res)
                console.log('res', res)
                // _this.confirm(file)
            })
            return file
        }
    }
}
</script>

 Can encapsulate compressed video code

  • Directory src/utils/ffmpeg.js
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'

// 压缩视频
const squeezVideo = async (file, filename, filetype, width, height) => {
    console.log('file', file)
    console.log('filename', filename)
    console.log('filetype', filetype)
    console.log('width', width)
    console.log('height', height)
    // 分辨率
    const resolution = `${width / 2}x${height / 2}`
    // 实例化ffmpeg
    const ffmpeg = createFFmpeg({
        // ffmpeg路径
        corePath: 'ffmpeg-core.js',
        // 日志
        log: true
        // 进度
        // progress: ({ ratio }) => {
        //     msg = `完成率: ${(ratio * 100.0).toFixed(1)}%`
        // }
    })
    console.log('file---', file)
    var { name } = file
    // msg = '正在加载 ffmpeg-core.js'
    // 开始加载
    await ffmpeg.load()
    // msg = '开始压缩'
    // 把文件加到ffmpeg   写文件
    ffmpeg.FS('writeFile', name, await fetchFile(file))
    // await ffmpeg.run('-i', name, '-b', '2000000', '-fs', '4194304', '-preset medium', 'superfast', 'put.mp4')
    // 开始压缩视频
    await ffmpeg.run('-i', name, '-b', '2000000', '-crf', '23', '-fs', '4194304', '-s', resolution, 'put.mp4')
    // msg = '压缩完成'
    // 压缩所完成,   读文件  压缩后的文件名称为 put.mp4
    const data = ffmpeg.FS('readFile', 'put.mp4')
    // 转换压缩后的视频格式  当前为 blob 格式
    var res = transToFile(data, filename, filetype)
    return new Promise((result, reject) => {
        result({
            filed: res
        })
    })
}

// 类型转换 blob 转换 file
const transToFile = (data, filename, filetype) => {
    var filed = []
    console.log(data)
    // 转换bolb类型
    const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
    // 这么写是因为文件转换是异步任务
    const transToFile = async (blob, fileName, fileType) => {
        return new window.File([blob], fileName, { type: fileType })
    }
    const textContain = transToFile(blob, filename, filetype)
    // 转换完成后可以将file对象传给接口
    textContain.then((res) => {
        filed.push(res)
        console.log('res', res)
    })
    return filed
}
export { squeezVideo }

Precautions:

ffmpeg is a very powerful video editing tool. You can study it yourself. The above code can be encapsulated by yourself. In addition, ffmpeg cannot be used in WeChat environment or enterprise micro environment, and the code will not execute.

Effect video

ffmpeg compressed video

If you can’t see the video, please go to my homepage to watch it.

 There is another plug-in that seems to work video-conversion.js but I can’t find the official website. If anyone has successfully researched it, please give me a kick.

If there are any shortcomings in the article, please correct me.

Guess you like

Origin blog.csdn.net/Youareseeing/article/details/132466508