Android中WebRTC传输MP4转文件异常:字节数组列表生成文件无法播放
问题分析与修复方案
你的问题根源出在文件分块存储和DataChannel发送逻辑的两个细节错误,导致最终合并的文件虽然大小一致,但混入了多余的无效字节,破坏了MP4的文件结构,所以无法正常播放。下面逐一拆解问题并给出修复代码:
核心问题1:分块存储时未保留实际读取长度
你用固定大小的byte[] chunk = new byte[260000]读取文件,但最后一次读取的字节数大概率小于260000。直接把整个chunk数组存入sentFileByte,会把数组中未被填充的默认0字节也存进去,这些多余的无效字节写入最终文件后,会彻底打乱MP4的格式结构。
核心问题2:DataChannel发送时ByteBuffer操作错误
你写了ByteBuffer bb = ByteBuffer.wrap(b); bb.put(b);,这里wrap(b)已经把b数组完整包装进ByteBuffer了,再调用put(b)会尝试把b数组再次写入缓冲区——但此时缓冲区的容量刚好等于b的长度,执行这个操作要么直接抛出BufferOverflowException,要么发送重复的错误数据,导致接收的块内容和原文件不符。
修复后的完整代码
1. 发送端:正确分块存储文件
FileInputStream is = new FileInputStream(file); byte[] chunk = new byte[260000]; int chunkLen = 0; sentFileByte = new ArrayList<>(); while ((chunkLen = is.read(chunk)) != -1) { // 关键:只保留实际读取到的字节,丢弃数组中未被使用的部分 byte[] actualChunk = new byte[chunkLen]; System.arraycopy(chunk, 0, actualChunk, 0, chunkLen); sentFileByte.add(actualChunk); } is.close(); // 务必关闭输入流,避免资源泄漏
2. 发送端:正确的DataChannel发送逻辑
byte[] b = sentFileByte.get(index); // 直接用wrap包装数组即可,无需额外执行put操作 ByteBuffer bb = ByteBuffer.wrap(b); dataChannel.send(new DataChannel.Buffer(bb, true));
3. 接收端:更严谨的文件合并逻辑
接收端的核心逻辑没问题,但建议用finally块确保流的关闭,避免异常导致资源泄漏:
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/" + fileName; File file = new File(path); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(file); for (byte[] chunk : receivedFileByteArr) { fileOutputStream.write(chunk); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
额外优化建议
- 发送文件前,先把文件总块数和文件名通过DataChannel发送给接收端,让接收端明确知道需要接收的块数量,避免漏接或多接。
- 给每个块加上序号标识,接收端按序号排序后再合并——因为WebRTC DataChannel默认是不可靠无序的,如果需要可靠有序传输,初始化DataChannel时要设置
ordered: true参数。
内容的提问来源于stack exchange,提问作者Tushar Monirul
相关产品推荐
相关产品推荐

