代码其实很简单,主要是要知道H264帧数据结构。分析H264码流结构的文章一大把,自己网上搜索一下就知道了。
背景:
h264+aac封装mp4格式的时候,需要获取视频流的sps,pps。
封装mp4文件格式的大体方案
使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件(硬解码的方式) (纯java)
使用MP4v2将H264/H265码流以及AAC音频封装成MP4格式(软解码的方式)(JNI+C)
使用FFmpeg将H264/H265码流以及AAC音频封装成MP4格式(软解码的方式)(JNI+C)
"csd-0" 和 "csd-1" 是什么,对于 H264 视频的话,它对应的是 sps 和 pps,对于 AAC 音频的话,对应的是 ADTS,做音视频开发的人应该都知道,它一般存在于编码器生成的 IDR 帧之中。创建并配置 codec。配置 codec 时,若手动创建 MediaFormat 对象的话,一定要记得设置 "csd-0" 和 "csd-1" 这两个参数。 "csd-0" 和 "csd-1" 这两个参数一定要和接收到的帧对应上。
c
/**
* 判断I针中有没有sps pps
* @param type 0==264 1==265
* @param data
* @return
*/
public static boolean ISIFrameData(int type, byte[] data) {
int nalType;
if (type == 0) {
int FF_H264_SPS_NAL = 7;
int FF_H264_PPS_NAL = 8;
nalType = data[4] & 0x1f;
XLog.e("","h264 nalType=== "+nalType);
if (FF_H264_SPS_NAL == nalType ||
FF_H264_PPS_NAL == nalType
) {
return true;
}
} else if (type == 1){
int FF_HEVC_VPS_NAL = 32;
int FF_HEVC_PPS_NAL = 34;
int FF_HEVC_SPS_NAL = 33;
nalType = (data[4] & 0x7e) >> 1;
XLog.e("","h265 nalType=== "+nalType);
if (FF_HEVC_VPS_NAL == nalType ||
FF_HEVC_PPS_NAL == nalType ||
FF_HEVC_SPS_NAL == nalType){
return true;
}
}
return false;
}
/**
* 获取I帧里面的 sps pps 信息
* @param type 0==264 1==265
* @param frame 帧数据
* @return
*/
public static List<byte []> getPPSByKeyFrameData(int type , byte[] frame){
Map<Integer,Integer> map=new HashMap<>();
int save_x=0;
List<byte[]> list=new ArrayList<>(2);
byte[]sps,pps;
if(type==0){//h264
int nalType=frame[4]&0x1f;//判断I帧,然后根据具体情况获取sps,pps
if(nalType==7){
//[Start Code]:Start Code 用于标示这是一个NALU 单元的开始(也称分隔符),必须是"00 00 00 01" 或"00 00 01"。
//关键帧是00 00 00 01
for (int i = 0; i < frame.length-3; i++) {
if(frame[i]==0&&frame[i+1]==0&&frame[i+2]==0&&frame[i+3]==1){
map.put(save_x,i);
save_x++;
}
}
int spsLength=map.get(1)-map.get(0)-4;
int spsOffset=map.get(0)+3;
sps=new byte[spsLength];
System.arraycopy(frame,spsOffset,sps,0,spsLength);
int ppsLength=map.get(2)-map.get(1)-4;
int ppsOffset=map.get(1)+3;
pps=new byte[ppsLength];
System.arraycopy(frame,ppsOffset,pps,0,ppsLength);
list.add(sps);
list.add(pps);
}
}
return list;
}