React Native Expo FileSystem读视频转Base64内存分配失败问题求解
问题根因
你遇到的OOM(内存不足)报错本质是一次性将整个视频文件读取到内存并转码为Base64的操作导致的:Base64编码会把二进制体积扩大33%,一个50MB的视频转完会占接近70MB内存,不同安卓厂商对单应用的连续内存分配上限配置不同,Oppo A3s上你录制的视频体积较小可以正常运行,三星A51上如果视频更大或者系统内存限制更严格就会触发分配失败。
解决方案
方案1:优先替换Base64上传,改用Multipart表单直传(最优)
直接上传二进制文件不需要转码,既节省33%的传输体积,也完全避免大内存占用,Expo FileSystem 原生支持表单上传,示例代码:
const upload = async () => { try { const result = await FileSystem.uploadAsync( '你的后端上传接口地址', videoUri, { httpMethod: 'POST', uploadType: FileSystem.UploadType.MULTIPART, fieldName: 'video', // 后端接收文件的字段名 mimeType: 'video/mp4', parameters: { // 其他需要传给后端的额外参数 userId: 'xxx' } } ); const res = JSON.parse(result.body); return res; } catch (e) { console.error('上传失败', e); } }
方案2:如果后端必须接收Base64格式,分片转码拼接
如果业务要求必须传Base64,可以用分片读取的方式,每次只读取一小块文件转码,避免一次性占用大内存:
// 默认每片2MB,可根据设备性能调整大小 const encodeBase64ByChunk = async (fileUri, chunkSize = 2 * 1024 * 1024) => { const fileInfo = await FileSystem.getInfoAsync(fileUri); const fileSize = fileInfo.size; let base64Str = ''; let offset = 0; while (offset < fileSize) { const chunk = await FileSystem.readAsStringAsync(fileUri, { encoding: FileSystem.EncodingType.Base64, offset, length: Math.min(chunkSize, fileSize - offset) }); base64Str += chunk; offset += chunkSize; } return base64Str; }; const upload = async () => { const base64 = await encodeBase64ByChunk(videoUri); const result = await myAPI(base64); }
方案3:源头限制视频体积
录制视频时通过参数限制分辨率和码率,降低生成的视频文件体积,从源头减少内存压力:
// 录制时设置低分辨率 const recordVideo = async () => { if (cameraRef.current) { const video = await cameraRef.current.recordAsync({ quality: Camera.Constants.VideoQuality['720p'], // 降低分辨率,不要用4K/1080p maxDuration: 30, // 限制最长录制30秒 bitrate: 2 * 1024 * 1024 // 2Mbps码率,可根据需求调整 }); setVideoUri(video.uri); } }
内容的提问来源于stack exchange,提问作者fxbayuanggara
相关产品推荐
相关产品推荐

