Android 8三星设备使用SCameraCaptureSession调用setRepeatingRequest报错
我之前也碰到过类似的坑,在Android 8的三星设备上用Camera2 API录制视频时正好遇到这个崩溃,给你分享下解决思路和具体步骤:
问题根源
Android 8(API 26)开始,Camera2 API对Surface的有效性校验变得更严格,尤其是三星设备会额外检查Surface是否完成了完整的初始化流程。低版本系统可能允许你提前把MediaRecorder的Surface绑定到CaptureRequest,但Android 8的三星设备会直接抛出IllegalArgumentException,因为此时MediaRecorder的Surface还没完成配置(比如还没调用prepare())。
具体解决方案
确保MediaRecorder的Surface完全初始化后再传入CaptureSession
一定要先完成MediaRecorder的所有配置(输出格式、编码、文件路径、视频分辨率等),调用mediaRecorder.prepare()之后,再获取它的Surface。绝对不能提前获取Surface再去配置MediaRecorder,顺序错了就会触发这个异常。
示例流程:// 1. 先配置MediaRecorder的各项参数 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setOutputFile(outputFilePath); mediaRecorder.setVideoEncodingBitRate(10000000); mediaRecorder.setVideoFrameRate(30); // 这里要注意选择Camera支持的尺寸,后面会讲 mediaRecorder.setVideoSize(recorderWidth, recorderHeight); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); // 2. 调用prepare()完成初始化 mediaRecorder.prepare(); // 3. 此时再获取有效的Surface Surface recorderSurface = mediaRecorder.getSurface();在CaptureSession配置完成后再创建CaptureRequest
必须等到SCameraCaptureSession的onConfigured()回调触发后,再创建包含MediaRecorder Surface的CaptureRequest并调用setRepeatingRequest。这一步是确保CaptureSession已经正确识别并配置了传入的Surface。
示例代码:// 假设已经有previewSurface用于预览 List<Surface> surfaces = Arrays.asList(previewSurface, recorderSurface); cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { // 这里才是安全创建录制请求的时机 try { CaptureRequest.Builder recordRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); recordRequestBuilder.addTarget(previewSurface); recordRequestBuilder.addTarget(recorderSurface); // 提交重复请求开始录制 session.setRepeatingRequest(recordRequestBuilder.build(), null, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { // 处理配置失败的逻辑,比如提示用户重试 } }, backgroundHandler);匹配Camera支持的视频尺寸
三星Android 8设备对Surface尺寸的匹配要求很严格,必须确保MediaRecorder设置的视频尺寸是当前Camera支持的输出尺寸。可以通过CameraCharacteristics获取支持的尺寸列表,选择最合适的那一个:// 获取Camera的特性 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); StreamConfigurationMap configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); // 获取MediaRecorder支持的输出尺寸 Size[] supportedSizes = configMap.getOutputSizes(MediaRecorder.class); // 选择和你期望的分辨率最匹配的尺寸(这里可以自己实现chooseOptimalSize方法) Size optimalSize = chooseOptimalSize(supportedSizes, desiredWidth, desiredHeight); // 设置给MediaRecorder mediaRecorder.setVideoSize(optimalSize.getWidth(), optimalSize.getHeight());提前校验Surface有效性
在提交CaptureRequest前,可以先检查Surface是否有效,避免传入无效的Surface导致崩溃:if (recorderSurface != null && recorderSurface.isValid()) { // 安全创建并提交请求 } else { // 重新初始化MediaRecorder和Surface }
总结
这个问题本质是Android 8开始的API行为变更加上三星设备的严格校验导致的,只要按照正确的顺序初始化MediaRecorder和Surface,确保尺寸匹配,并且在CaptureSession配置完成后再提交请求,就能解决这个崩溃问题。
内容的提问来源于stack exchange,提问作者lior_13

