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;
}