FFmpeg简单使用:解封装h264----提取SPSPPS-创新互联
前言
成都创新互联是一家专业提供抚州企业网站建设,专注与网站设计、成都网站建设、H5技术、小程序制作等业务。10年已为抚州众多企业、政府机构等服务。创新互联专业网站设计公司优惠进行中。我们从flv和mp4等文件解封装读取的AVPacket并没有SPS、PPS数据,而是保存在 AVFormatContext ->streams ->codecpar ->extradata里面,下面我们打开一个flv文件看一下
分析一下这块数据,起始位置:0980 大小:39 结束位置:09a6
前4个字节:
0x01: version
0x42: avc profile (首个SPS的第1个字节)
0xc0: avc compatibility (首个SPS的第2个字节)
0x28: avc level (首个SPS的第3个字节,可以发现后面0x0989位置的3个字,和这3个是一样的)
第5个字节:
0xff:
6_bit: 默认111111
2_bit: 数据长度-1:avcc格式是extradata | [length] [nalu] | [length][nalu],这里length所占的字节数就是3(11)+ 1 = 4
第6个字节:
0xe1: [111 00001]
3_bit: 默认 111
5_bit: 接下来的sps或pps的个数::这里为1
第7 8个字节:
0x00 0x18: 表示接下来sps或者pps的长度为24
第9个字节:
0x67: [0110 0111] nalu_type为7,表示SPS,就是说从0988到099f这24个数据为sps
第33个字节:9 (sps_pos) + 24(sps_size)
0x01: 接下来的sps或pps的个数::这里为1
第34 35字节:
0x00 0x04: 表示接下来sps或者pps的长度为4
第36个字节:
0x68: [0110 1000] nalu_type为8,表示PPS
编码
int VideoSend::ParseExtradata(VideoState* is)
{
uint8_t* start_data = is->video_st->codecpar->extradata;
uint8_t* extradata = is->video_st->codecpar->extradata;
int extradata_size = is->video_st->codecpar->extradata_size;
std::cout<< "extradata_size:"<< extradata_size<< std::endl;
for (int i = 0; i< extradata_size; ++i) {
printf(" %02x", *(extradata+i));
}
std::cout<< std::endl;
// 1. 跳过前4个字节
extradata = extradata +4;
// 2. byte_5:获取nalu length所占字节数
d->nalu_length_bytes = (*extradata++ & 0x03) + 1;
std::cout<< "nalu_length_bytes:"<< (int)d->nalu_length_bytes<< std::endl;
int sps_seen = 0, pps_seen = 0;
while ((extradata - start_data)< extradata_size) {
// 3. byte_6:获取下面sps/pps个数
uint8_t item_nb = *extradata++ & 0x1f;
std::cout<< "item_nb:"<< (int)item_nb<< std::endl;
if (!item_nb) {
continue;
}
int ret;
while(item_nb--){
// 4. byte_7 byte_8: 表示sps或者pps长度
uint16_t uint_size = (extradata[0]<< 8) | extradata[1];
std::cout<< "uint_size: "<< uint_size<< std::endl;
// 5. 数据异常
if ((extradata - start_data + uint_size + 2) >extradata_size) {
std::cout<< "extradata exception "<< uint_size<< std::endl;
goto failed;
}
// 6. byte_9: 检查包类型
uint8_t nalu_type = extradata[2];
nalu_type = nalu_type & 0x1f;
std::cout<< "nalu_type: "<< (int)nalu_type<< std::endl;
// 7. sps
if (nalu_type == 7 && !sps_seen) {
std::cout<< "--sps--"<< std::endl;
// a.分配内存
if (ret = av_reallocp(&d->sps_pkt.buf, uint_size)< 0) {
goto failed;
}
// b.数据拷贝
memcpy(d->sps_pkt.buf, extradata + 2, uint_size);
sps_seen = 1;
d->sps_pkt.size = uint_size;
}
// 8. pps
if (nalu_type == 8 && !pps_seen) {
std::cout<< "--pps--"<< std::endl;
// a.分配内存
if (ret = av_reallocp(&d->pps_pkt.buf, uint_size)< 0) {
goto failed;
}
// b.数据拷贝
memcpy(d->pps_pkt.buf, extradata + 2, uint_size);
pps_seen = 1;
d->pps_pkt.size = uint_size;
}
extradata = extradata + 2 + uint_size;
}
}
if (pps_seen && sps_seen) {
std::cout<< "sps:";
for (int i = 0; i< d->sps_pkt.size; ++i) {
printf(" %02x", d->sps_pkt.buf[i]);
}
std::cout<< std::endl;
std::cout<< "pps:";
for (int i = 0; i< d->pps_pkt.size; ++i) {
printf(" %02x", d->pps_pkt.buf[i]);
}
std::cout<< std::endl;
return 0;
}
failed:
std::cout<< "VideoSend::ParseExtradata failed."<< std::endl;
if (d->pps_pkt.buf) {
av_free(d->pps_pkt.buf);
d->pps_pkt.buf = NULL;
}
if (d->sps_pkt.buf) {
av_free(d->sps_pkt.buf);
d->sps_pkt.buf = NULL;
}
return -1;
}
输出:
extradata_size:40
01 42 c0 1e ff e1 00 18 67 42 c0 1e db 02 c0 c7 96 a1 00 00 03 00 01 00 00 03 00 32 8f 16 2e e0 01 00 05 68 ca 83 cb 20
nalu_length_bytes:4
item_nb:1
uint_size: 24
nalu_type: 7
--sps--
item_nb:1
uint_size: 5
nalu_type: 8
--pps--
sps: 67 42 c0 1e db 02 c0 c7 96 a1 00 00 03 00 01 00 00 03 00 32 8f 16 2e e0
pps: 68 ca 83 cb 20
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章题目:FFmpeg简单使用:解封装h264----提取SPSPPS-创新互联
分享地址:http://pwwzsj.com/article/dojdjp.html