将大视频转为Base64字符串触发java.lang.OutOfMemoryError求助
解决大视频转Base64时的OutOfMemoryError问题
问题现象
将大视频文件编码为Base64字符串时,抛出java.lang.OutOfMemoryError,小视频可正常转换。错误信息如下:
java.lang.OutOfMemoryError: Failed to allocate a 341424000 byte allocation with 25165824 free bytes and 78MB until OOM, target footprint 479725424, growth limit 536870912
当前实现会把整个视频文件的字节读取到内存中的ByteArrayOutputStream,再转为Base64字符串——大视频的字节数组加上Base64字符串会占用远超VM内存限制的空间,直接触发OOM。
解决方案
针对你后续需要解码回字节并在VideoView播放的需求,推荐以下几种方案:
1. 流式处理Base64编码/解码(最优方案)
避免将整个视频和Base64字符串加载到内存,改用流式编码直接将Base64内容写入文件,解码时再流式读取文件还原视频,最后用VideoView播放本地文件。
流式编码代码示例
public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == 200) { Uri selectedMediaUri = data.getData(); String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.MIME_TYPE }; Cursor cursor = getContext().getContentResolver().query(selectedMediaUri, columns, null, null, null); if (cursor == null) { Toast.makeText(getContext(), "无法获取视频路径", Toast.LENGTH_SHORT).show(); return; } cursor.moveToFirst(); int pathColumnIndex = cursor.getColumnIndex(columns[0]); String contentPath = cursor.getString(pathColumnIndex); cursor.close(); // 定义Base64输出文件路径(缓存目录,避免占用用户空间) String base64OutputPath = getContext().getCacheDir() + "/video_base64.txt"; try (FileInputStream inputStream = new FileInputStream(contentPath); FileOutputStream fileOutputStream = new FileOutputStream(base64OutputPath); Base64OutputStream base64OutputStream = new Base64OutputStream(fileOutputStream, Base64.DEFAULT)) { byte[] buffer = new byte[8192]; int bytesRead; // 分块读取视频字节,流式编码为Base64写入文件 while ((bytesRead = inputStream.read(buffer)) != -1) { base64OutputStream.write(buffer, 0, bytesRead); } // 保存Base64文件路径,供后续解码使用 Client.videoBase64FilePath = base64OutputPath; } catch (IOException e) { Toast.makeText(getContext(), "处理视频失败", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } } }
流式解码并播放示例
// 解码Base64文件为视频文件,并用VideoView播放 public void decodeAndPlayVideo() { String decodedVideoPath = getContext().getCacheDir() + "/decoded_video.mp4"; try (FileInputStream base64InputStream = new FileInputStream(Client.videoBase64FilePath); FileOutputStream videoOutputStream = new FileOutputStream(decodedVideoPath); Base64InputStream base64DecoderStream = new Base64InputStream(base64InputStream, Base64.DEFAULT)) { byte[] buffer = new byte[8192]; int bytesRead; // 分块读取Base64内容,流式解码为视频字节写入文件 while ((bytesRead = base64DecoderStream.read(buffer)) != -1) { videoOutputStream.write(buffer, 0, bytesRead); } // 用VideoView播放解码后的本地视频文件 videoView.setVideoPath(decodedVideoPath); videoView.start(); } catch (IOException e) { e.printStackTrace(); } }
2. 直接操作文件/Uri(跳过Base64转换)
如果你的场景允许直接传递视频文件路径或Uri,完全不需要转Base64——VideoView本身支持直接加载本地文件或Content Uri,这是最省资源的方案:
public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && requestCode == 200) { Uri selectedMediaUri = data.getData(); // 直接保存Uri,后续用VideoView加载 Client.videoUri = selectedMediaUri; // 直接播放示例 videoView.setVideoURI(selectedMediaUri); videoView.start(); } }
3. 临时增大堆内存(治标不治本)
在AndroidManifest.xml的<application>标签中添加android:largeHeap="true",可以让应用获得更大的内存分配额度,但这只是临时缓解,超大视频仍会触发OOM,不推荐作为核心解决方案:
<application ... android:largeHeap="true"> ... </application>
内容的提问来源于stack exchange,提问作者Atomic
相关产品推荐
相关产品推荐

