ffmpeg 推流 在H264中插入SPS、PPS 头

1. SPS PPS头的重要性
SPS PPS 头在编解码H264时非常重要,里面不仅包含了许多关于视频流的相关信息:比如宽高等。还标志着一个视频流的开头。

一般视频流前开头第一帧是SPS 第二帧是PPS 第三帧才是I帧。目前在网上看到加入SPS PPS头都是在解码时加入,解码时加入ffmpeg有个特别的过滤方法av_bitstream_filter_filter()。编码目前只能深入了解编码底层,找到I帧并且在I帧前插入SPS PPS头。否则即使你是使用ffmpeg编码的视频流,用ffplay播放也是缺少SPS PPS头的。

对于是应该在编码加入SPS PPS头还是解码加入,哪一边兼容其实不重要,我认为最标准的是两边都做这样的兼容,这样程序才更加强壮。作为推流端在推流时加入SPS PPS 头,拉流时判断是否找得到SPS PPS 头,若没有,则加上SPS PPS头。这样就程序就会健壮许多。

2.如何在判断推流时H264文件是否含有SPS PPS头。

使用ffmpeg编码,目前新版的ffmpeg编码接口是avcodec_send_frame()和avcodec_receive_packet() ,前者将存放YUV的AVFrame放入,后者将存放编好的H264 AVPacket取出。然后我们可以用fwrite在av_interleaved_write_frame()封装并发送前写二进制,然后推荐用Binary Viewer查看写的h264二进制文件。

FILE *file = fopen("C:\\Users\\admin\\Desktop\\123456.h264", "wb");//(放在编码和播放的循环外面)
fwrite(enc_packet.data, sizeof(enc_packet), 1, file);

但是不一定开头就是SPS和PPS或者I帧,而且这时一般是没有SPS 和 PPS头的,查看二进制文件时搜索一下00000001来查找。

SPS 十六进制值为:0x67
PPS 十六进制值为:0x68
I帧 十六进制值为:0x65
但是在I帧和SPS开头都会有00000001(PPS接在SPS后,是一体的)
如果找到00 00 00 01 67,则这一帧为I帧。
在这里插入图片描述

3.如何插入SPS PPS头
SPS和PPS头在你用ffmpeg编码时已经获取到了,存放在编码器上下文AVCodecContext的extradata中,可以从中取出并插入H264中。

前面说到了SPS和PPS是在I帧之前

所以我们就应该在每一个AVPacket的h264中查找i帧

AVPacket中有个重要的参数可以用来判断是否含有i帧:flags
用flag与AV_PKT_FLAG_KEY进行与操作就可以判断当前这一帧是否为I帧。
找到I帧后,在I帧前面插入extradata就完成插帧,记得扩大指针的大小。

//声明尽量不要在推流的while循环里做,避免内存泄漏
AVPacket enc_packet;
char* cPacketData = new char(oCodecCtx->extradata_size  * sizeof(char*));
uint8_t* cExtradata = (uint8_t *)malloc((100000) * sizeof(uint8_t));
...
...
...
...
...
...
if (enc_packet.flags &AV_PKT_FLAG_KEY)//找到带I帧的AVPacket
{
	cPacketData = (char*)enc_packet.data; 
	int n = 0;
	while ((char*)enc_packet.data)
	{
		//printf("%c\n", cPacketData[n]);
		if (cPacketData[n] == 0 && cPacketData[n + 1] == 0 && cPacketData[n + 2] == 0 && cPacketData[n + 3] == 1 && cPacketData[n + 4] == 101)
		{
		//找到I帧,插入SPS和PPS
		memcpy(cExtradata, oCodecCtx->extradata, oCodecCtx->extradata_size);
		memcpy(cExtradata + oCodecCtx->extradata_size, enc_packet.data, enc_packet.size);//&enc_packet.data[0]
		enc_packet.size += oCodecCtx->extradata_size;
		enc_packet.data = cExtradata;
		break;
		}
		if (n == enc_packet.size)
		{
		break;
		}
				cPacketData++;
				n++;
			}
			
		}

基本到这里都完成了插帧。

FFmpeg是一个非常强大的开源工具集,用于处理音视频数据,包括解码、编码、转码、流处理、过滤等。RTSP(Real Time Streaming Protocol)是一种网络流媒体传输控制协议,常用于控制流媒体服务器上的流媒体数据的回放。H264是一种视频编码标准,广泛应用于视频压缩,由于其高压缩比和良好的视频质量,被广泛用于直播和视频存储。 使用FFmpeg进行RTSP流的H264推流,通常是将摄像或其他视频源的实时视频数据编码成H264格式,并通过RTSP协议传输到流媒体服务器或者接收端。这个过程可以简单分为以下几个步骤: 1. 捕获视频源:首先,需要使用FFmpeg的视频捕获功能,可以是通过摄像、网络摄像或者其他视频输入设备获取原始视频流。 2. 视频编码:将捕获到的原始视频流使用H264编码器进行压缩编码。 3. 推流:编码后的视频数据通过RTSP协议推送到指定的服务器或播放器。 一个基本的FFmpeg命令行示例来实现这个功能可能如下所示: ``` ffmpeg -i input -vcodec libx264 -acodec copy -f rtsp rtsp://server_address:port/stream_name ``` 其: - `-i input` 指定输入文件或设备,例如 `video.mp4` 或 `/dev/video0`。 - `-vcodec libx264` 指定视频编码器为H264。 - `-acodec copy` 表示音频编码不变,直接拷贝(如果有的话)。 - `-f rtsp` 指定输出格式为RTSP。 - `rtsp://server_address:port/stream_name` 指定RTSP流的服务器地址和流名称。 使用FFmpeg进行RTSP推流时需要注意的是,网络状况、编码参数和服务器配置都会影响推流的稳定性和视频质量。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值