复制Payload流时出现异常,Camera预览帧传输问题求助
我之前做Android实时视频传输的时候也碰到过类似的流复制异常,结合你描述的Camera预览帧传输场景,大概率是帧数据处理或流操作环节出了问题,咱们一步步来排查:
首先排查预览帧的格式是否匹配传输要求
Camera的onPreviewFrame返回的字节数组默认是YUV格式(多数设备是NV21),如果你的sendFramesOfImages方法期望的是压缩后的图像流(比如JPEG),直接把原始YUV字节转成InputStream传输会导致对方无法解析,进而抛出流复制异常。
解决方法是先把YUV数据压缩成JPEG再生成流:@Override public void onPreviewFrame(byte[] data, Camera camera) { Camera.Parameters params = camera.getParameters(); Camera.Size size = params.getPreviewSize(); // 将NV21格式的YUV数据转成JPEG字节数组 YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { // 压缩质量可根据需求调整(0-100) yuvImage.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, baos); byte[] jpegBytes = baos.toByteArray(); // 用try-with-resources自动关闭流,避免资源泄漏 try (ByteArrayInputStream is = new ByteArrayInputStream(jpegBytes)) { sendFramesOfImages(is); } } catch (IOException e) { Log.e("CameraPreview", "Frame processing error", e); } }检查流的创建与复用是否正确
如果你复用了同一个InputStream对象,或者没有在每次回调时创建新的流,会导致流的读取指针已经到末尾,后续读取时抛出异常。务必保证每次onPreviewFrame回调都创建全新的ByteArrayInputStream,并且用try-with-resources语法自动关闭流,避免资源泄漏。确认线程安全问题
onPreviewFrame是在Camera的内部回调线程执行的,如果sendFramesOfImages方法是在主线程或者其他线程中处理流,可能出现并发读写流的情况,导致复制过程中出错。
可以用Handler把流处理任务切换到指定线程,比如:private final Handler mWorkHandler = new Handler(Looper.getMainLooper()); // 或者自定义线程的Looper @Override public void onPreviewFrame(byte[] data, Camera camera) { // 先在回调线程处理YUV转JPEG Camera.Parameters params = camera.getParameters(); Camera.Size size = params.getPreviewSize(); YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, baos); byte[] jpegBytes = baos.toByteArray(); // 切换到目标线程执行传输 mWorkHandler.post(() -> { try (ByteArrayInputStream is = new ByteArrayInputStream(jpegBytes)) { sendFramesOfImages(is); } catch (IOException e) { e.printStackTrace(); } }); }检查sendFramesOfImages内部的流复制逻辑
异常提示是复制流时出错,可能是这个方法内部的读取逻辑有问题,比如误用了available()方法来判断总长度(available()仅返回当前可读取的字节数,不是流的总长度),或者没有正确处理流的结束标记(read()返回-1)。
正确的流复制逻辑应该是这样的:public void sendFramesOfImages(InputStream is) throws IOException { byte[] buffer = new byte[4096]; // 用合适大小的缓冲区 int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { // 这里替换成你的发送逻辑,比如写入Socket输出流 yourOutputStream.write(buffer, 0, bytesRead); } yourOutputStream.flush(); // 确保数据全部发送 }
内容的提问来源于stack exchange,提问作者NullPointerExcepzion




