Android音视频编码的(sps pps adts)

本文讨论了在Android中使用mediacodec进行视频编码时遇到的问题,特别是关于如何正确处理SPS(SequenceParameterSet)和PPS(PictureParameterSet)以及AAC音频的ADTS头部对编码结果的影响,指出编码器预置选项可能导致色彩问题,需在编码后手动添加关键帧头。
摘要由CSDN通过智能技术生成

Android使用mediacodec编码,编码过程不说了,说个比较特别的问题

补充知识:帧类型判断:编码出来的数据的第5个字节与0x1f进行与运算,outputBuffer.get(4) & 0x1F;如果这个值是7那就是spspps,如果是5就是I帧,剩下的就是p帧(没用过B帧)

android 使用mediacodec编码,有个参数是MediaFormat.KEY_PREPEND_HEADER_TO_SYNC_FRAMES:指的就是:"prepend-sps-pps-to-idr-frames",给每个I帧前添加sps和pps,

如果这个参数设置为Format.setInteger(MediaFormat.KEY_PREPEND_HEADER_TO_SYNC_FRAMES, 0),那么编码的结果是第一帧是sps和pps,后面就不会再有sps了,所以编码出来的帧就是:75111111...11111115111111...11111151111......;

如果这个参数设置为Format.setInteger(MediaFormat.KEY_PREPEND_HEADER_TO_SYNC_FRAMES, 1),那么编码出来的帧就是:711111...11117111...11117111......;7这个帧里面包含I帧。

以上两种设置编码出来的数据根据这类型判断都正常,但是如果添加了sps编码出来的数据播放就有问题了,把数据写成文件去播放的时候发现色彩图像色彩不对了,不添加sps就是正确的。测试设备是个荣耀的平板android12的。

所以配置编码器的时候添加sps行不通,只能编码出来后手动添加。

if (type == 7 || type == 8) { //sps帧时,先保存下来
    spspps_size = mBufferInfo.size;
    outputBuffer.get(spspps, 0, spspps_size);
    mBufferInfo.size = 0;
}
else if (type == 5) { //I帧时,把sps添加到最前面
    if(mFileMuxer != null) {
        byte[] outStream = new byte[mBufferInfo.size + spspps_size];
        System.arraycopy(spspps, 0, outStream, 0, spspps_size);
        outputBuffer.get(outStream, spspps_size, mBufferInfo.size);

        mFileMuxer.writeData(0, outStream, mBufferInfo.size, mBufferInfo.presentationTimeUs , 1);
        isAddKeyFrame = true;
    }
} else { //p帧不用添加
if (isAddKeyFrame) { 
    if(mFileMuxer != null) {
        byte[] outStream = new byte[mBufferInfo.size];
        outputBuffer.get(outStream, 0, mBufferInfo.size);
        mFileMuxer.writeData(0, outStream, mBufferInfo.size, mBufferInfo.presentationTimeUs , 0);
    }

}

aac编码也是同样的问题,配置编码器的时候有个参数,KEY_IS_ADTS,true 表示 AAC 音频流为 ADTS 格式,mediaFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);设置后编码出来的数据用vlc播放不了,如果有adts头是可以播放的。所以又是手动添加,adts的方法网上找的。

if(mFileMuxer != null) {

    byte[] outStream = new byte[mBufferInfo.size+7]; //编码出来的数据长度再加adts的长度7
    outputBuffer.get(outStream, 7, mBufferInfo.size);
    addADTStoPacket(outStream, mBufferInfo.size+7, mParams.getAudioChannelCount()); //方法在下面 
    mFileMuxer.writeData(1, outStream, mBufferInfo.size+7, mBufferInfo.presentationTimeUs, 1);

}


public void addADTStoPacket(byte[] packet, int packetLen, int chancfg) { //packetLen包含adts的长度和编码数据的长度
    int profile = 2; //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;
    int freqIdx = 3; //见后面注释avpriv_mpeg4audio_sample_rates中441000对应的数组下标,来自ffmpeg源码
    int chanCfg = chancfg; //见后面注释channel_configuration

/*int avpriv_mpeg4audio_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350};

channel_configuration: 表示声道数chanCfg
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved

*/

    // fill in ADTS data
    packet[0] = (byte)0xFF;
    packet[1] = (byte)0xF1;
    packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
    packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));
    packet[4] = (byte)((packetLen&0x7FF) >> 3);
    packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);
    packet[6] = (byte)0xFC;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值