You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:44:54