FFmpeg常用指令记录&sdp中提取sps/pps信息&sps/pps(STAP-A解析)


Author:Peter
Location:FZU
Date: 2022-04-15

:如人饮水,冷暖自知。


ffmpeg编码/推流指令,ffprobe分析H264码流指令。win10系统,git bash终端操作(可使用linux相关指令)。


1.ffmpeg利用x264编码YUV文件为H264

  • 将yuv420压缩成h264 -r:帧率,-g:GOPsize,-bf:B帧数量,-b:v 编码速率,-bufsize:码率控制缓冲区大小
./ffmpeg.exe -s 1920x1080 -i ParkScene_1920x1080.yuv -c:v libx264 -r 25 -g 50 -bf 0 -b:v 2000k -bufsize 2500k ParkScene_in.h264

2.ffmpeg通过RTP封包推送H264码流

注意事项,ffmpeg推送rtp流,IDR帧前不像Live555会采用两个packet封装sps/pps,而是直接一个STAP-A打包方式将sps及pps一同并入一个packet,即一个IDR帧前只含有一个sps&pps信息的packet,如下图抓包显示。

./ffmpeg.exe -re -i ParkScene_in.h264  -an -c copy -f rtp -ssrc 10 rtp://127.0.0.1:9900?pkt_size=1316 > 1.sdp
  • ffmpeg 推RTP流,IDR帧中sps/pps抓包信息

IDR帧sps/pps信息
  开头十六进制18的后五位二进制为11000(十进制为24,属于STAP-A封包),即00 1a为第一个nalu(sps)[67 64… 92 40]的长度,00 05为第二个nalu(pps)[68 eb cc b2 2c]的长度。固接收端解析STAP-A包时,需要将18 00 1a 替换成00 00 00 01,00 05替换成00 00 00 01,记00 00 00 01为一个nalu的起始码。

  • 接收端解析STAP-A(sps/pps)
#include<iostream>
#include<string>
#include<vector>

using namespace std;

union LENGTH  //可以采用联合体,共用内存空间,length与byte[2]
{
	uint16_t length;
	uint8_t  byte[2];
};



//0x00 0x1a   0000 0000 0001 1010 = 26 
void testSTAP_A()
{
	char sps_pps[] = { 0x18,0x00,0x1a,0x67,0x64,0x00,0x28,
						 0xac,0xb2,0x00,0xf0,0x04,0x4f,0xcb,0x08,
						 0x00,0x00,0x03,0x00,0x08,0x00,0x00,0x03,
						 0x01,0x90,0x78,0xc1,0x92,0x40,0x00,0x05,
						 0x68,0xeb,0xcc,0xb2,0x2c
	};
	int sps_length = 0;
	int pps_length = 0;
	//电脑是小端存储,地址低位存放数字低位,这样转过来为0x1a,0x00,0x00,0x00 十进制为26
	for (int i = 2, j = 0; i >= 1; --i, ++j)
		memcpy((char*)&sps_length + j, sps_pps + i, 1);
	cout << "sps_length=" << sps_length << endl;

#if 1  //采用联合体计算sps长度,也要考虑到小端存储0x00 0x1a (0x1a在低地址)
	LENGTH sps;
	for (int i = 0; i < 2; ++i)
	{
		sps.byte[i] = sps_pps[2 - i];
	}
	cout << sps.length << endl;

#endif 

	pps_length = sizeof(sps_pps) - sps_length - 5;
	//电脑是小端存储,地址低位存放数字低位,这样转过来为00 00 00 01
	uint32_t start_code = 0x01000000;
	vector<char> parse_sps_pps(sizeof(sps_pps) + 2 * 4 - 5);
	memcpy(parse_sps_pps.data(), &start_code, 4);
	memcpy(parse_sps_pps.data() + 4, sps_pps + 3, sps_length);
	memcpy(parse_sps_pps.data() + 4 + sps_length, &start_code, 4);
	memcpy(parse_sps_pps.data() + 8 + sps_length, sps_pps + 5 + sps_length, pps_length);
}

int main()
{

	testSTAP_A();
	
	return 0;
}
  • 指令生成的sdp信息:
SDP:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 58.76.100
m=video 9900 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAKKyyAPAET8sIAAADAAgAAAMBkHjBkkA=,aOvMsiw=; profile-level-id=640028
  • 提取sdp中的sps/pps信息(base64编码,逗号是分割sps,pps)

sprop-parameter-sets=Z2QAKKyyAPAET8sIAAADAAgAAAMBkHjBkkA=,aOvMsiw=

  其中sps信息: Z2QAKKyyAPAET8sIAAADAAgAAAMBkHjBkkA=
    pps信息: aOvMsiw=

  • C/C++代码提取sps/pps
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
	ifstream inf("..\\ffmpeg_bin\\1.sdp");
	string oneline;
	string sps_sdp;
	string pps_sdp;
	string sps_pps_sdp;

	int sps_start,pps_start,pps_end;

	while (true)
	{
		getline(inf, oneline);
		if (inf.eof() == true)
			break;
		cout << oneline << "\n";
		if ((sps_start = oneline.find("-sets=")) >0 && (pps_end = oneline.find("; profile")) >0 )
		{
			sps_start += 6;
			sps_pps_sdp.assign(oneline.data() + sps_start, oneline.data() + pps_end);
		}

	}
	if ((pps_start = sps_pps_sdp.find(",")) > 0)
	{
		sps_sdp.assign(sps_pps_sdp.data(), sps_pps_sdp.data() + pps_start);
		pps_sdp.assign(sps_pps_sdp.data() + pps_start + 1, sps_pps_sdp.data() + sps_pps_sdp.size());
		cout << "sps:"<<sps_sdp << "\t" <<"pps:"<< pps_sdp << endl;
	}
	return 0;
}

//----------------运行结果如下:----------------------
SDP:
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 58.76.100
m=video 9900 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QAKKyyAPAET8sIAAADAAgAAAMBkHjBkkA=,aOvMsiw=; profile-level-id=640028

sps:Z2QAKKyyAPAET8sIAAADAAgAAAMBkHjBkkA=    pps:aOvMsiw=

3.ffprobe分析h264文件指令

  • 查看h264码流I/B/P帧分布
./ffprobe.exe -v error -show_frames ParkScene_in.h264 | grep "pict_type"
  • 统计h264码流总帧数
./ffprobe.exe -v error -count_frames -select_streams v:0  -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 ParkScene_in.h264
  • 查看h264码流信息
./ffprobe.exe -v error -show_streams ParkScene_in.h264

  has_b_frames=0意味着264码流中无B帧

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值