纯前端实现视频首尾剪裁效果实例页面

回到相关文章 »

效果:

视频资源

代码:

JS代码:
// 顶层变量存储文件对象,供后续合成使用
let videoFile = null;

const {
    Input,
    Output,
    Conversion,
    ALL_FORMATS,
    BlobSource,
    Mp4OutputFormat,
    BufferTarget,
    CanvasSink
} = Mediabunny;

const range = document.getElementById('clipRange');

// 视频选择与预览
fileVideo.addEventListener('change', async (event) => {
    const file = event.target.files[0];
    if (file) {
        videoFile = file;
        
        const input = new Input({
            formats: ALL_FORMATS,
            source: new BlobSource(file)
        });

        const videoTrack = await input.getPrimaryVideoTrack();
        if (videoTrack) {
            const decodable = await videoTrack.canDecode();
            if (decodable) {
                const sink = new CanvasSink(videoTrack, {
                    // 缩略图尺寸
                    width: 160
                });

                // 选10张图作为缩略图
                const startTimestamp = await videoTrack.getFirstTimestamp();
                const endTimestamp = await videoTrack.computeDuration();

                // range选择的min max 设置
                range.innerHTML = '<input type="range" data-tips="${value}s" is="ui-range" width="100%" multiple step="0.1" min="'+ Math.round(startTimestamp * 10) / 10 +'" max="'+ Math.round(endTimestamp * 10) / 10 +'">';

                // 生成10个时间戳
                // 10个时间戳,每个时间戳间隔相同
                const timestamps = Array.from({ length: 10 }).map(
                    (t, index) => startTimestamp + index * (endTimestamp - startTimestamp) / 10
                );

                // Loop over these timestamps
                for await (const result of sink.canvasesAtTimestamps(timestamps)) {
                    const canvas = result.canvas;
                    const url = canvas.toDataURL('image/jpeg');
                    const img = document.createElement('img');
                    img.src = url;
                    img.alt = `缩略图${result.timestamp}`;
                    videoThumb.appendChild(img);
                }
            }
        }
    }
});

form.addEventListener('submit', async (event) => {
    event.preventDefault();

    const submit = form.querySelector('button');
    submit.textContent = '剪裁中...';   
    submit.disabled = true;

    const input = new Input({
        formats: ALL_FORMATS,
        source: new BlobSource(videoFile)
    });
    const output = new Output({
        format: new Mp4OutputFormat(), // The format of the file
        target: new BufferTarget()
    });

    const eleRange = range.querySelector('input');  
    const conversion = await Conversion.init({
        input,
        output,
        trim: {
            start: eleRange.from,
            end: eleRange.to
        },
    });

    conversion.onProgress = function (progress) {
        submit.textContent = `剪裁中...${Math.round(progress * 100)}%`;
    };

    await conversion.execute();

    const buffer = output.target.buffer;
    const url = URL.createObjectURL(new Blob([buffer]));
    result.innerHTML = `<video src="${url}" controls></video>`;
    submit.textContent = '开始剪裁';
    submit.disabled = false;
});