iOS转Android投屏H.264编解码容器格式兼容问题咨询
解决iOS投屏Android的H.264编解码容器兼容问题
核心问题分析
你遇到的“not in avi mode”错误,本质是iOS VideoToolbox输出的H.264裸流格式与Android MediaCodec的解码要求不匹配——iOS默认输出Annex-B格式的NALU(网络抽象层单元)流,但如果NALU的起始码、SPS/PPS传递方式不符合Android解码器的预期,就会被误识别为AVI容器格式,导致解码失败。
具体解决方案
1. 修正NALU起始码处理
iOS VideoToolbox输出的原始NALU不带起始码,自定义头部容易导致Android无法识别NALU边界。正确做法是给每个NALU添加4字节起始码(0x00000001):
- 对SPS、PPS、IDR帧及其他NALU单元,在数据前拼接
0x00 0x00 0x00 0x01; - 关键帧(IDR)必须跟随完整的SPS和PPS,且这两个NALU要单独发送(同样带起始码),不能与IDR帧合并。
2. 确保SPS/PPS的正确传递
Android解码器必须先获取SPS(序列参数集)和PPS(图像参数集)才能正确初始化解码:
- iOS端:编码输出的第一个CMSampleBuffer通常包含SPS和PPS,要提取这两个NALU数据,添加起始码后立即发送,之后再发送IDR帧和其他帧;
- Android端:收到SPS/PPS后,将其配置到
MediaFormat中:// 假设spsData和ppsData是从网络接收的字节数组 ByteBuffer spsBuffer = ByteBuffer.wrap(spsData); ByteBuffer ppsBuffer = ByteBuffer.wrap(ppsData); MediaFormat format = MediaFormat.createVideoFormat("video/avc", 1080, 2340); // 替换为iOS编码的分辨率 format.setByteBuffer("csd-0", spsBuffer); format.setByteBuffer("csd-1", ppsBuffer); format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); // 匹配iOS编码帧率
3. 统一H.264 Profile与Level
避免iOS自动选择过高的Level导致Android无法兼容:
- 将iOS端的
kVTCompressionPropertyKey_ProfileLevel从kVTProfileLevel_H264_Main_AutoLevel改为明确的kVTProfileLevel_H264_Main_4_1(Redmi 7A支持的最高Level):NSDictionary *compressionProps = @{ kVTCompressionPropertyKey_ConstantBitRate: @6144000, kVTCompressionPropertyKey_ProfileLevel: kVTProfileLevel_H264_Main_4_1, kVTCompressionPropertyKey_MaxKeyFrameInterval: @60, kVTCompressionPropertyKey_RealTime: @YES, kVTCompressionPropertyKey_Quality: @1.0 };
4. 修正Android MediaCodec解码配置
确保Android解码器按裸H.264流处理,而非容器格式:
- 初始化解码器时不要设置任何容器相关参数,仅配置必要的视频属性;
- 接收网络数据时,按NALU边界分割后再送入解码器,避免一次性传递大量无分割的数据;
- 解码时给配置数据(SPS/PPS)标记
BUFFER_FLAG_CODEC_CONFIG:// 发送SPS/PPS到解码器 int inputBufferIndex = decoder.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferIndex); inputBuffer.clear(); inputBuffer.put(spsPpsData); // 拼接了起始码的SPS+PPS数据 decoder.queueInputBuffer(inputBufferIndex, 0, spsPpsData.length, 0, MediaCodec.BUFFER_FLAG_CODEC_CONFIG); }
5. 验证流格式正确性
用FFmpeg工具捕获iOS发送的流,检查是否为标准Annex-B格式:
ffprobe -show_streams captured_stream.h264
输出中如果显示codec_name=h264且profile=Main,说明流格式正确。
内容的提问来源于stack exchange,提问作者GDSM
相关产品推荐
相关产品推荐

