升级targetSDK至31后三星A系列Android12设备SurfaceView黑屏
解决targetSDK 31升级后三星A系列Android 12设备SurfaceView黑屏问题
这个问题我之前在适配Android 12的时候也碰到过类似的情况,尤其是三星的定制系统对SurfaceView的行为有一些特殊调整,结合targetSDK升级到31后的API变更,我给你几个可行的排查和解决方案:
1. 确保解码器在Surface完全就绪后再配置
Android 12(API 31)对Surface的可用性校验变得更严格,如果你在Surface还未完全创建完成时就调用decoder.configure(),很可能导致解码器无法正确绑定Surface,从而出现黑屏。建议把解码器的配置逻辑移到SurfaceHolder.Callback的surfaceCreated回调中:
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { // 这里Surface已经完全就绪,再初始化解码器 MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 1280, 720); try { decoder.configure(mediaFormat, holder.getSurface(), null, 0); decoder.start(); } catch (IllegalStateException | IOException e) { // 即使无法获取用户日志,建议在本地添加异常捕获逻辑,方便后续排查 e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 可选:如果Surface尺寸变化,调整解码器输出参数 } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 及时释放解码器资源,避免内存泄漏 if (decoder != null) { decoder.stop(); decoder.release(); decoder = null; } } });
2. 替换SurfaceView为TextureView
三星的Android 12定制系统对SurfaceView的兼容性不如TextureView,TextureView作为View的子类,渲染逻辑更灵活,不受SurfaceFlinger的部分限制,很多时候能直接解决黑屏问题。替换后的代码示例如下:
TextureView mTextureView = findViewById(R.id.video_texture_view); mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { Surface decoderSurface = new Surface(surface); MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 1280, 720); try { decoder.configure(mediaFormat, decoderSurface, null, 0); decoder.start(); } catch (Exception e) { e.printStackTrace(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // 适配Surface尺寸变化 } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (decoder != null) { decoder.stop(); decoder.release(); decoder = null; } surface.release(); return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { // 可选:监听帧更新事件 } });
3. 补充MediaFormat的必要参数
API 31对解码器的配置参数要求更严格,仅指定宽高和格式可能不足以让解码器正常输出帧。建议补充帧率、码率,以及H264必需的SPS/PPS数据(如果有的话):
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 1280, 720); // 设置帧率,根据你的视频实际帧率调整 mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); // 设置合理的码率,示例值可根据实际情况调整 mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1280 * 720 * 30 * 2); // 如果你的H264流包含SPS和PPS数据,一定要添加到MediaFormat中 byte[] spsData = ...; // 从视频流中解析出的SPS字节数组 byte[] ppsData = ...; // 从视频流中解析出的PPS字节数组 mediaFormat.setByteBuffer("csd-0", ByteBuffer.wrap(spsData)); mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(ppsData)); decoder.configure(mediaFormat, surface, null, 0);
4. 确认硬件加速和权限配置
SurfaceView依赖硬件加速,Android 12可能默认的配置有变化,建议在Manifest中明确开启硬件加速:
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:hardwareAccelerated="true" <!-- 确保开启硬件加速 --> android:theme="@style/AppTheme"> ... </application>
如果视频数据来自外部存储,还要确保已申请Android 12对应的存储权限(READ_MEDIA_VIDEO),避免因权限问题导致解码失败。
内容的提问来源于stack exchange,提问作者Aishwarya Aishu
相关产品推荐
相关产品推荐

