React客户端上传前视频压缩方案故障排查求助
React视频压缩功能修复方案
问题分析
你的代码存在以下核心问题导致压缩功能失效:
video.onloadedmetadata事件绑定错误,错误赋值为Promise,且未等待视频加载完成就执行后续逻辑- 依赖
useState的mediaStream获取流,但useState是异步更新的,导致后续代码拿到的是null mediaRecorder.ondataavailable事件绑定错误,用Promise替代了事件回调,无法正确捕获数据块- 未触发
MediaRecorder.stop(),导致录制过程无法结束,无法生成完整的压缩视频Blob
修复后的完整代码
import React, { useState, useRef } from 'react' function Test2() { const [file, setFile] = useState(null) const [compressedFile, setCompressedFile] = useState(null) const videoRef = useRef(null) const handleFileSelection = (event) => { setFile(event.target.files[0]) } const handleCompression = async () => { if (!file) return const videoUrl = URL.createObjectURL(file) const video = document.createElement('video') // 配置视频属性,绕过浏览器自动播放限制 video.src = videoUrl video.muted = true video.playsInline = true // 等待视频元数据加载完成 await new Promise((resolve) => { video.onloadedmetadata = resolve }) // 开始播放视频才能捕获流 await video.play() // 捕获视频流,设置目标帧率 const stream = video.captureStream(25) // 配置MediaRecorder,指定格式与压缩比特率 const mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/mp4', videoBitsPerSecond: 500000 // 500kbps,可按需调整数值控制压缩程度 }) const chunks = [] // 正确绑定数据捕获事件 mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { chunks.push(event.data) } } // 录制完成后生成压缩文件 mediaRecorder.onstop = () => { const recordedBlob = new Blob(chunks, { type: 'video/mp4' }) setCompressedFile(URL.createObjectURL(recordedBlob)) // 清理临时URL,避免内存泄漏 URL.revokeObjectURL(videoUrl) } // 启动录制 mediaRecorder.start() // 视频播放结束后停止录制并清理流 video.onended = () => { mediaRecorder.stop() stream.getTracks().forEach(track => track.stop()) } } return ( <> <input type="file" accept="video/*" onChange={handleFileSelection} /> <button onClick={handleCompression} disabled={!file}>Compress</button> {file && ( <video ref={videoRef} src={URL.createObjectURL(file)} controls muted playsInline style={{ maxWidth: '400px', margin: '10px 0' }} /> )} {compressedFile && ( <div> <p>压缩完成:</p> <video src={compressedFile} controls muted playsInline style={{ maxWidth: '400px', margin: '10px 0' }} /> <a href={compressedFile} download="compressed-video.mp4">下载压缩视频</a> </div> )} </> ) } export default Test2
关键修复说明
- 等待视频加载与播放:将视频加载过程封装为Promise,确保元数据加载完成后再捕获流;添加
muted和playsInline属性,绕过浏览器自动播放限制,保证视频能正常播放从而捕获流。 - 直接使用流对象:不再依赖
useState存储mediaStream,而是在视频加载完成后直接使用捕获到的流,避免异步更新导致的延迟问题。 - 正确绑定MediaRecorder事件:将
ondataavailable改为普通回调函数,仅收集有效数据块,避免空数据干扰。 - 控制录制生命周期:监听视频
onended事件,播放结束后停止录制并关闭流轨道,确保生成完整的压缩视频;同时添加URL对象清理,避免内存泄漏。 - 配置压缩参数:在
MediaRecorder构造函数中指定视频比特率,通过调整videoBitsPerSecond值控制压缩程度,数值越小压缩率越高、质量越低。
内容的提问来源于stack exchange,提问作者Mohit
相关产品推荐
相关产品推荐

