对H.264帧类型判断方法
背景描述
我们经常在网络直播推流或者客户端拉流的时候,需要对获取到的H.264视频帧进行判断后处理,我们经常获取到各种不同的视频数据0x67 0x68 0x65 0x61,0x27 0x28 0x25 0x21,0x47 0x48 0x45 0x41,各种不同的编码芯片有时间出来的NAL Header规则不大一样,那么我们怎么来以统一的方式判断帧的类型呢:sps、pps、IDR、P
如下转自EasyDarwin开源贡献者Kim的博客:http://blog.csdn.net/jinlong0603/article/details/70170042
H264
H264在网络传输的是NALU,NALU的结构是:NAL头+RBSP,实际传输中的数据流如图所示:
其中NAL头占一个字节,其低5个bit位表示NAL type,具体如下表:
| NAL type | NAL类型 |
|---|---|
| 0 | 未使用 |
| 1 | 非IDR的片 |
| 2 | 片数据A分区 |
| 3 | 片数据B分区 |
| 4 | 片数据C分区 |
| 5 | IDR图像的片 |
| 6 | 补充增强信息单元(SEI) |
| 7 | 序列参数集(SPS) |
| 8 | 图像参数集(PPS) |
| 9 | 分界符 |
| 10 | 序列结束 |
| 11 | 码流结束 |
| 12 | 填充 |
| 13..23 | 保留 |
| 24..31 | 不保留 |
RBSP 为原始字节序列载荷。
NAL type为5,则此帧为I帧即关键帧,type为1时为非关键帧(P帧…)。
在实际的H264数据帧中,往往帧NAL type前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧,然后是P帧…
EasyPusher/EasyRTMP 视频流推送
EasyPusher和EasyRTMP是通过调用摄像机SDK、拉取RTSP流、读mp4文件等方式获取到H264视频流及音频视频流到本地作为视频源,再以RTSP、RTMP方式推送给流媒体服务器。它们都是支持Windows、Linux、Android、iOS、ARM等全平台的视频流推送程序。
下面介绍下它们在获取到视频流到本地后如何区分I帧和P帧等,然后推送的:
//这段代码是从文件中读取h264数据,然后推送给服务器
unsigned char *ptr=new unsigned char [sample_size];
fread(ptr, sample_size, 1, g_fin);
//写一帧数据 --- 可以直接进行网络推送
//fwrite(ptr, sample_size, 1, fout);
EASY_AV_Frame avFrame;
memset(&avFrame, 0x00, sizeof(EASY_AV_Frame));
/*
*ptr的前4字节是帧分分割符00 00 00 01 , 第5个字节是NAL type
*/
unsigned char naltype = ( (unsigned char)ptr[4] & 0x1F);
avFrame.pBuffer = (unsigned char*)ptr;
avFrame.u32AVFrameLen = sample_size;
avFrame.u32VFrameType = (naltype==0x05)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P;
avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG;
avFrame.u32TimestampSec = lTimeStamp/1000000;
avFrame.u32TimestampUsec = (lTimeStamp%1000000);
如果视频源不是文件,而是IPCamera 或者RTSP流等,在他们的视频流回调中可能已经告知当前帧是I帧还是P帧,就省去了判断NAL type的步骤。
HI_S32 NETSDK_APICALL OnStreamCallback(HI_U32 u32Handle,/* 句柄 */
HI_U32 u32DataType, /* 数据类型,视频或音频数据或音视频复合数据 */
HI_U8* pu8Buffer, /* 数据包含帧头 */
HI_U32 u32Length, /* 数据长度 */
HI_VOID* pUserData /* 用户数据*/
)
{
HI_S_AVFrame* pstruAV = HI_NULL;
HI_S_SysHeader* pstruSys = HI_NULL;
if (u32DataType == HI_NET_DEV_AV_DATA)
{
pstruAV = (HI_S_AVFrame*)pu8Buffer;
if (pstruAV->u32AVFrameFlag == HI_NET_DEV_VIDEO_FRAME_FLAG)
{
if(fPusherHandle == 0 ) return 0;
if(pstruAV->u32AVFrameLen > 0)
{
unsigned char* pbuf = (unsigned char*)(pu8Buffer+sizeof(HI_S_AVFrame));
EASY_AV_Frame avFrame;
memset(&avFrame, 0x00, sizeof(EASY_AV_Frame));
avFrame.u32AVFrameLen = pstruAV->u32AVFrameLen;
avFrame.pBuffer = (unsigned char*)pbuf;
avFrame.u32VFrameType = (pstruAV->u32VFrameType==HI_NET_DEV_VIDEO_FRAME_I)?EASY_SDK_VIDEO_FRAME_I:EASY_SDK_VIDEO_FRAME_P;
avFrame.u32AVFrameFlag = EASY_SDK_VIDEO_FRAME_FLAG;
avFrame.u32TimestampSec = pstruAV->u32AVFramePTS/1000;
avFrame.u32TimestampUsec = (pstruAV->u32AVFramePTS%1000)*1000;
EasyPusher_PushFrame(fPusherHandle, &avFrame);
}
}
else
if (pstruAV->u32AVFrameFlag == HI_NET_DEV_AUDIO_FRAME_FLAG)
{
if(fPusherHandle == 0 ) return 0;
if(pstruAV->u32AVFrameLen > 0)
{
//不同IPCamera,这里数据头不一样,需要根据各自的SDK跳过对应的大小。有些可能没有自定义数据
unsigned char* pbuf = (unsigned char*)(pu8Buffer+sizeof(HI_S_AVFrame));
EASY_AV_Frame avFrame;
memset(&avFrame, 0x00, sizeof(EASY_AV_Frame));
avFrame.u32AVFrameLen = pstruAV->u32AVFrameLen-4;//去掉厂家自定义的4字节头
avFrame.pBuffer = (unsigned char*)pbuf+4;
avFrame.u32AVFrameFlag = EASY_SDK_AUDIO_FRAME_FLAG;
avFrame.u32TimestampSec = pstruAV->u32AVFramePTS/1000;
avFrame.u32TimestampUsec = (pstruAV->u32AVFramePTS%1000)*1000;
EasyPusher_PushFrame(fPusherHandle, &avFrame);
}
}
}
else
if (u32DataType == HI_NET_DEV_SYS_DATA)
{
pstruSys = (HI_S_SysHeader*)pu8Buffer;
printf("Video W:%u H:%u Audio: %u \n", pstruSys->struVHeader.u32Width, pstruSys->struVHeader.u32Height, pstruSys->struAHeader.u32Format);
}
return HI_SUCCESS;
}
有了数据源,只需要调用libEasyPusher或libEasyRTMP就可以完成RTSP、RTMP直播推送了!
下载
EasyDarwin服务器下载:https://github.com/EasyDarwin/EasyDarwin或者国内镜像http://git.oschina.net/easydarwin/EasyDarwin
EasyPusher 下载:https://github.com/EasyDarwin/EasyPusher
EasyRTMP 下载:https://github.com/EasyDarwin/EasyRTMP
获取更多信息
Copyright © EasyDarwin.org 2012-2017

对H.264帧类型判断方法的更多相关文章
- H.264帧结构详解
6.1.2.源码简单浏览 6.1.3.重点1:h.264帧结构6.1.4.重点2:帧结构分析软件的使用6.1.5.重点3:rtsp网络编程6.1.6.重点4:wireshark网络抓包工具的使用 6. ...
- 获得H.264视频分辨率的方法
转自:http://www.cnblogs.com/likwo/p/3531241.html 在使用ffmpeg解码播放TS流的时候(例如之前写过的UDP组播流),在连接时往往需要耗费大量时间.经过d ...
- 【转载】 H264的I/P/B帧类型判断
http://blog.csdn.net/zhuweigangzwg/article/details/44152239 这里首先说明下H264的结构: 00 00 00 01/00 00 01-> ...
- 使用ASP.NET 上传文件 三种类型判断方法(后缀,MIME,数据流)
#region 一. 安全性比较低,把文本文件1.txt改成1.jpg照样可以上传,但其实现方法容易理解,实现也简单,所以网上很多还是采取这种方法. Boolean fileOk = false; s ...
- javascript类型判断方法
判断javascript中的类型,共有四种常用的方法 var a=6; var b="str"; var c=true; var arr=[]; typeof 用于基本类型的判断 ...
- JS万金油的类型判断方法
Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
- H.264视频压缩标准
H.264 这部分一直在讲,但是却没有系统的来说.接下来要详细. 参看:H.264视频压缩标准 一.简介 H.264是最新的视频压缩标准,它也称为MPEG-4 Part 10或AVC(高级视频编码). ...
- jQuery使用(十二):工具方法之type()之类型判断
type()的使用 类型判断方法之is...() 实现原理可以参考我的另一篇js源码剖析博客: 类型和原生函数及类型转换(二:终结js类型判断) $.type( undefined ) === &qu ...
- (转载)H.264码流的RTP封包说明
H.264的NALU,RTP封包说明(转自牛人) 2010-06-30 16:28 H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) ...
随机推荐
- [Codeforces Round #297 Div. 2] E. Anya and Cubes
http://codeforces.com/contest/525/problem/E 学习了传说中的折半DFS/双向DFS 先搜前一半数,记录结果,然后再搜后一半数,匹配之前结果. #include ...
- 【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...
- GridView从行寻找到该控件,以及从该控件获知该行
原文发布时间为:2008-08-01 -- 来源于本人的百度文章 [由搬家工具导入] GridView从行寻找到该控件: protected void Button3_Click(object sen ...
- hdu 1065(推公式)
I Think I Need a Houseboat Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...
- mybatis trim
eg: select * from user <trim prefix="WHERE" prefixoverride="AND |OR"> < ...
- SD 胡策 Round 1 T3 彩尾巴猹的二进制数
发现一个区间[L,R]代表的2进制数是3的倍数,当且仅当从L开始的后缀二进制值 - 从R+1开始的后缀二进制值 是 3 的倍数 (具体证明因为太简单而被屏蔽). 于是我们就可以在每个点维护从它开始的后 ...
- MQTT协议介绍
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.pdf MQTT 文档 http://mqtt.org/new/wp-c ...
- js中call、apply、bind那些事2
前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call.apply.bind的问题,比如… 怎么利用call.apply来求一个数组中最大或者最小值 如何利用call.apply来做继承 ...
- JavaScript : 零基础打造自己的jquery类库
写作不易,转载请注明出处,谢谢. 文章类别:Javascript基础(面向初学者) 前言 在之前的章节中,我们已经不依赖jQuery,单纯地用JavaScript封装了很多方法,这个时候,你一定会想, ...
- sql标准支持了事务隔离级别
事务隔离级别 尽管数据库为用户提供了锁的DML操作方式,但直接使用锁管理是非常麻烦的,因此数据库为用户提供了自动锁机制.只要用户指定会话的事务隔离级别,数据库就会分析事务中的SQL语句,然后自动为事务 ...