You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将大视频转为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:05:26