使用RTMP拉视频流后I帧、P帧、B帧、sps、pps帧等如何判断,请用C++代码举例并表明注释

时间: 2024-02-01 19:01:54 浏览: 23
在使用RTMP拉视频流后,可以通过解析视频流的NALU(Network Abstraction Layer Unit)来判断视频帧类型,以及获取SPS、PPS等信息。下面是一个简单的C++代码示例: ```cpp #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> using namespace std; // NALU类型定义 #define NALU_TYPE_SLICE 1 // 非IDR图像的片 #define NALU_TYPE_DPA 2 // 非IDR图像的片 #define NALU_TYPE_DPB 3 // 非IDR图像的片 #define NALU_TYPE_DPC 4 // 非IDR图像的片 #define NALU_TYPE_IDR 5 // IDR图像中的片 #define NALU_TYPE_SEI 6 // 补充增强信息单元 #define NALU_TYPE_SPS 7 // 序列参数集 #define NALU_TYPE_PPS 8 // 图像参数集 #define NALU_TYPE_AUD 9 // 分界符 #define NALU_TYPE_EOSEQ 10 // 序列结束 #define NALU_TYPE_EOSTREAM 11 // 码流结束 #define NALU_TYPE_FILL 12 // 填充 // NALU结构体定义 typedef struct NALU_t { int startcodeprefix_len; // 码流中开始码的长度,一般为4 unsigned len; // 去掉起始码后,NALU数据部分的长度 unsigned max_size; // nalu的最大长度 int forbidden_bit; // 禁止位,始终为0 int nal_reference_idc; // NALU重要性,0~3依次降低 int nal_unit_type; // NALU类型 char* buf; // NALU数据缓冲区地址 } NALU_t; int FindStartCode2(unsigned char *Buf) { if(Buf[0]!=0 || Buf[1]!=0 || Buf[2]!=1) return 0; // 检查起始码前三个字节是否为0x000001 else return 1; } int FindStartCode3(unsigned char *Buf) { if(Buf[0]!=0 || Buf[1]!=0 || Buf[2]!=0 || Buf[3]!=1) return 0; // 检查起始码前四个字节是否为0x00000001 else return 1; } int GetAnnexbNALU(NALU_t *nalu) { int pos = 0; int StartCodeFound, rewind; unsigned char *Buf; if ((Buf = (unsigned char*)calloc(nalu->max_size , sizeof(char))) == NULL) return 0; nalu->startcodeprefix_len = 3; if (3 != fread(Buf, 1, 3, h264stream)) { free(Buf); return 0; } if (FindStartCode2(Buf)) { // 找到3字节起始码 nalu->startcodeprefix_len = 3; pos = 3; } else { // 找到4字节起始码 if (1 != fread(Buf+3, 1, 1, h264stream)) { free(Buf); return 0; } if (FindStartCode3(Buf)) { // 找到4字节起始码 nalu->startcodeprefix_len = 4; pos = 4; } else { // 没有找到起始码 free(Buf); return -1; } } // 查找下一个起始码前的字节数 StartCodeFound = 0; rewind = 0; while (!StartCodeFound) { if (feof(h264stream)) { nalu->len = (pos-1) - nalu->startcodeprefix_len; memcpy(nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len); nalu->forbidden_bit = nalu->buf[0] & 0x80; // 禁止位 nalu->nal_reference_idc = (nalu->buf[0] & 0x60) >> 5; // 重要性 nalu->nal_unit_type = (nalu->buf[0]) & 0x1f; // 类型 free(Buf); return pos-1; } Buf[pos++] = fgetc(h264stream); if (Buf[pos-1] == 0x00) rewind++; else { if (Buf[pos-1] == 0x01 && rewind >= 2) StartCodeFound = 1; else rewind = 0; } } // 找到下一个起始码前的字节数 rewind = (rewind == 2) ? 2 : 3; if (0 != fseek(h264stream, -rewind, SEEK_CUR)) { free(Buf); printf("GetAnnexbNALU: Cannot fseek in the bit stream file"); return 0; } // 去掉起始码,获取NALU数据部分长度 nalu->len = (pos-rewind) - nalu->startcodeprefix_len; memcpy(nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len); nalu->forbidden_bit = nalu->buf[0] & 0x80; // 禁止位 nalu->nal_reference_idc = (nalu->buf[0] & 0x60) >> 5; // 重要性 nalu->nal_unit_type = (nalu->buf[0]) & 0x1f; // 类型 free(Buf); return (pos-rewind); } int main() { // 打开视频流 FILE *h264stream = fopen("test.h264", "rb"); if (!h264stream) { printf("Can't open input video file.\n"); return 0; } // 初始化NALU结构体 NALU_t *nalu = (NALU_t*)calloc(1, sizeof(NALU_t)); if (!nalu) { printf("Alloc NALU_t failed.\n"); return 0; } // 设置最大NALU长度 nalu->max_size = 1024*1024; nalu->buf = (char*)calloc(nalu->max_size, sizeof(char)); if (!nalu->buf) { printf("Alloc NALU_t buf failed.\n"); return 0; } // 读取NALU数据 while (!feof(h264stream)) { int pos = GetAnnexbNALU(nalu); if (pos > 0) { // 判断NALU类型 switch (nalu->nal_unit_type) { case NALU_TYPE_SLICE: case NALU_TYPE_DPA: case NALU_TYPE_DPB: case NALU_TYPE_DPC: case NALU_TYPE_IDR: // I帧或P帧 break; case NALU_TYPE_SPS: // SPS帧 break; case NALU_TYPE_PPS: // PPS帧 break; default: // 其他帧类型 break; } } } // 关闭视频流 fclose(h264stream); // 释放内存 free(nalu->buf); free(nalu); return 0; } ``` 该代码打开一个H.264码流文件,然后从中读取NALU数据,并判断NALU类型。其中,`GetAnnexbNALU`函数用于从码流中读取一个NALU,`FindStartCode2`和`FindStartCode3`函数用于查找起始码。在判断NALU类型时,根据NALU类型的不同,可以判断出I帧、P帧、SPS帧、PPS帧等。由于H.264码流中的NALU是以起始码(0x000001或0x00000001)为分割的,因此需要在读取NALU数据时,先查找起始码,并去掉起始码后的数据才是NALU的有效数据。同时,SPS、PPS等信息也是以NALU的形式存在于码流中。

相关推荐

最新推荐

recommend-type

vue-video-player实现实时视频播放方式(监控设备-rtmp流)

主要介绍了vue-video-player实现实时视频播放方式(监控设备-rtmp流),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
recommend-type

树莓派使用python-librtmp实现rtmp推流h264的方法

今天小编就为大家分享一篇树莓派使用python-librtmp实现rtmp推流h264的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
recommend-type

Flex视频播放器(支持rtmp协议)开发代码

1访问red5服务器的flv视频进行播放.(rtmp协议) 2播放器的多种功能实现:VideoDisplay 播放视频、HSlider进度条、开始、暂停、停止、声音大小、全屏、当前时间/总时间等;
recommend-type

rtmp在浏览器中显示实时播放,不依赖flash插件

rtmp视频流转格式发送http-flv格式流,使rtmp视频流可以在浏览器中显示
recommend-type

python3将视频流保存为本地视频文件

使用python3+opencv3.3.1环境将视频流保存为本地视频文件,具体内容如下 1、利用opencv中的VideoCapture类获取视频流的链接,通过cv2的方法得到该视频流的帧数和每帧大小。 2、使用VideoWriter类进行视频编码 3、...
recommend-type

zigbee-cluster-library-specification

最新的zigbee-cluster-library-specification说明文档。
recommend-type

管理建模和仿真的文件

管理Boualem Benatallah引用此版本:布阿利姆·贝纳塔拉。管理建模和仿真。约瑟夫-傅立叶大学-格勒诺布尔第一大学,1996年。法语。NNT:电话:00345357HAL ID:电话:00345357https://theses.hal.science/tel-003453572008年12月9日提交HAL是一个多学科的开放存取档案馆,用于存放和传播科学研究论文,无论它们是否被公开。论文可以来自法国或国外的教学和研究机构,也可以来自公共或私人研究中心。L’archive ouverte pluridisciplinaire
recommend-type

实现实时数据湖架构:Kafka与Hive集成

![实现实时数据湖架构:Kafka与Hive集成](https://img-blog.csdnimg.cn/img_convert/10eb2e6972b3b6086286fc64c0b3ee41.jpeg) # 1. 实时数据湖架构概述** 实时数据湖是一种现代数据管理架构,它允许企业以低延迟的方式收集、存储和处理大量数据。与传统数据仓库不同,实时数据湖不依赖于预先定义的模式,而是采用灵活的架构,可以处理各种数据类型和格式。这种架构为企业提供了以下优势: - **实时洞察:**实时数据湖允许企业访问最新的数据,从而做出更明智的决策。 - **数据民主化:**实时数据湖使各种利益相关者都可
recommend-type

SPDK_NVMF_DISCOVERY_NQN是什么 有什么作用

SPDK_NVMF_DISCOVERY_NQN 是 SPDK (Storage Performance Development Kit) 中用于查询 NVMf (Non-Volatile Memory express over Fabrics) 存储设备名称的协议。NVMf 是一种基于网络的存储协议,可用于连接远程非易失性内存存储器。 SPDK_NVMF_DISCOVERY_NQN 的作用是让存储应用程序能够通过 SPDK 查询 NVMf 存储设备的名称,以便能够访问这些存储设备。通过查询 NVMf 存储设备名称,存储应用程序可以获取必要的信息,例如存储设备的IP地址、端口号、名称等,以便能
recommend-type

JSBSim Reference Manual

JSBSim参考手册,其中包含JSBSim简介,JSBSim配置文件xml的编写语法,编程手册以及一些应用实例等。其中有部分内容还没有写完,估计有生之年很难看到完整版了,但是内容还是很有参考价值的。