SPS、PPS 的头部信息 增加了额外的16字节的长度 sps/pps 按照关键帧处理
frame type : 关键帧 / 非关键帧 (4 bit)
CodecID : 7表示AVC CodecID 和frametype组合成一个字节 (4 bit) 0x17 / 0x27
fixed : 0x00(AVCDecoderConfigurationRecord) 0x00 0x00 0x00 (4 byte)
sps + pps数据
configurationVersion (1 byte) 0x01 版本
AVCProfileIndication (1 byte) sps[1] Profile
profile_compatibility (1 byte) sps[2] 兼容性
AVCLevelIndication (1 byte) sps[3] Profile level
lengthSizeMinusOne (1 byte) 0xff 包长数据所使用的字节数
sps number (1 byte) 0xe1 sps个数
sps data length (2 byte) sps长度
sps data sps实际内容
pps number (1 byte) 0x01 pps的个数
pps data length (2 byte) pps长度
pps data pps内容
char *body = packet->m_body;
int i = 0;
//0x17关键帧 frame type (4 bit)
// CodecID (4 bit)
body[i++] = 0x17;
//fixed (4 byte)
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
//版本 Profile 兼容性 ProfileLevel
body[i++] = 0x01;
body[i++] = sps[1];
body[i++] = sps[2];
body[i++] = sps[3];
//包长数据所使用的字节数
body[i++] = 0xff;
//sps个数
body[i++] = 0xe1;
//sps长度 (2 byte)
body[i++] = (sps_len >> 8) & 0xff;
body[i++] = sps_len & 0xff;
//sps实际内容
memcpy(&body[i], sps, sps_len);
i += sps_len;
//pps的个数
body[i++] = 0x01;
//pps长度 (2 byte)
body[i++] = (pps_len >> 8) & 0xff;
body[i++] = pps_len & 0xff;
//pps实际内容
memcpy(&body[i], pps, pps_len);
H264 增加了额外的9字节的长度
frame type : 1关键帧、2非关键帧 (4 bit)
CodecID : 7表示AVC (4 bit) 0x17/0x27 和frametype组合成一个字节
fixed : 0x01(NALU) 0x00 0x00 0x00 (4 byte)
data length : 长度信息(4 byte)
data : h264裸数据
char *body = packet->m_body;
int i = 0;
//0x17关键帧 frame type (4 bit)
//0x27非关键帧 CodecID (4 bit)
if (keyFrame) {
body[i++] = 0x17;
} else {
body[i++] = 0x27;
}
//fixed (4 byte) NALU
body[i++] = 0x01;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
//dataLength : 长度信息(4 byte)
body[i++] = (data_len >> 24) & 0xff;
body[i++] = (data_len >> 16) & 0xff;
body[i++] = (data_len >> 8) & 0xff;
body[i++] = data_len & 0xff;
//h264 裸数据
memcpy(&body[i], data, data_len);
LivePushActivity
package com.example.glivepush;
import android.os.Bundle;
import android.os.Environment;
import android.se.omapi.SEService;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.glivepush.camera.GCameraView;
import com.example.glivepush.push.BasePushEncoder;
import com.example.glivepush.push.GConnectListener;
import com.example.glivepush.push.PushEncodec;
import com.example.glivepush.push.PushVideo;
import com.example.glivepush.util.DisplayUtil;
public class LivePushActivity extends AppCompatActivity {
private PushVideo pushVideo;
private GCameraView gCameraView;
private boolean start = false;
private PushEncodec pushEncodec;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_push);
pushVideo = new PushVideo();
gCameraView = findViewById(R.id.cameraView);
pushVideo.setgConnectListener(new GConnectListener() {
@Override
public void onConnecting() {
Log.d("godv", "链接服务器中");
}
@Override
public void onConnectSuccess() {
Log.d("godv", "链接服务器成功");
pushEncodec = new PushEncodec(LivePushActivity.this, gCameraView.getTextureId());
pushEncodec.initEncodec(
gCameraView.getEglContext(),
DisplayUtil.getScreenWidth(LivePushActivity.this),
DisplayUtil.getScreenHeight(LivePushActivity.this),
44100,
2
);
pushEncodec.startRecord();
/*************************************直播推流-video-start***********************************/
pushEncodec.setOnMediaInfoListener(new BasePushEncoder.OnMediaInfoListener() {
@Override
public void onMediaTime(int times) {
}
@Override
public void onSPSPPSInfo(byte[] sps, byte[] pps) {
pushVideo.pushSPSPPS(sps, pps);
}
@Override
public void videoInfo(byte[] data, boolean keyFrame) {
pushVideo.pushVideoData(data, keyFrame);
}
});
/*************************************直播推流-video-end***********************************/
}
@Override
public void onConnectFail(String msg) {
Log.d("godv", msg);
}
});
}
public void startPush(View view) {
start = !start;
if (start) {
pushVideo.initLivePush("rtmp://192.168.0.14/myapp/mystream");
} else {
if (pushEncodec != null) {
pushEncodec.stopRecord();
pushEncodec = null;
}
}
}
}
BasePushEncoder
package com.example.glivepush.push;
import android.content.Context;
import android.media.MediaCodec;
import android.media.Me

本文介绍了H264编码中的SPS和PPS序列参数集的封装格式,并给出了具体的实现代码示例。针对不同的帧类型,文章详细解释了关键帧与非关键帧的数据组织方式,包括额外字节的增加及其在编码过程中的作用。
最低0.47元/天 解锁文章
1036

被折叠的 条评论
为什么被折叠?



