H264数据中获取PTS(计算出PTS)

原文地址: http://70565912.blog.51cto.com/1358202/533736/
只大概说明要点。更具体的方法恕不祥叙。
我的开源工程和很多开源项目都有详细完整的实现代码。
这些要点都是我自己学习的总结,无责任保证正确性。仅做参考。
如发现有问题请丢砖头,跪求各方高人指正错误。Orz
内容:
H264的ES原始数据一般是以NAL(Network Abstract Layer)的格式存在。可以直接用于文件存储和网络传输。每一个NALU(Network Abstract Layer Unit)数据,是由数据头+RBSP数据组成。
首先需要将数据流,分割成一个一个独立的NALU数据。
接着获取NALU的nal_type,i_nal_type的值等于0x7表示这个nalu是个sps数据包。找到并解析这个sps数据包,里面包含有非常重要的帧率信息
time_scale/num_units_in_tick=fps
然后根据nal_type判断slice(H264中的slice类似一个视频帧FRAME的概念)。其中nal_type值小于0x1,或大于0x5,表示这个NALU属于一个slice。
// 检查是否是slice
if ( i_nal_type < 1/NAL_SLICE/ || i_nal_type > 5/NAL_SLICE_IDR/ )
// 找到slice!!!!!
在找到slice的NALU后,可以逐字节将NALU的数据与0x80进行与运算,结果为真表示这个slice(视频帧FRAME)的结束位置。
// 判断是否帧结束
for (uint32_t i = 3; i < nal_length; i++)
{
if (p_nal[i] & 0x80)
{
// 找到frame_begin!!!!上一帧frame的结束,下一帧frame的开始
}
}
上面的这个代码是摘抄自FFMPEG。他实际作用是判断slice里面的first_mb_in_slice,即第1个宏块在slice中的位置,如果是一帧开始,这个字段的值肯定是标识第1个宏块。因此,也可以完整解析slice的头部信息,解析出first_mb_in_slice,如果是0(注意:这是1个哥伦布数值),即这个NALU是一帧的开始。

为什么这里的代码是逐字节判断0x80?我额外写点某大神的名言:程序猿不是十万个为什么,不是维基猿,程序猿是需求猿。如果某程序猿已经着手开始研究如何解析slice头部格式,他很自然的不会有这个疑问。

另外通过nal_type以及silice_type也可以判断出帧结束位置,VLC里面的代码就是这么干。

解析到位于帧结束位置的NALU,就可以判断出每一帧(slice)的开始和结尾。解析slice的slice_type,根据slice_type,可以判断出这个slice的IPB类型。
// 根据slice类型判断帧类型
switch(slice.i_slice_type)
{
case 2: case 7:
case 4: case 9:
p_flags = 0x0002/BLOCK_FLAG_TYPE_I/;
break;
case 0: case 5:
case 3: case 8:
p_flags = 0x0004/BLOCK_FLAG_TYPE_P
/;
break;
case 1:
case 6:
p_flags = 0x0008/BLOCK_FLAG_TYPE_B/;
break;
default:
p_flags = 0;
break;
}
从现在开始,就有两种办法来计算PTS了。
方法一、根据前后帧的IPB类型,可以得知帧的实际显示顺序,使用前面获取的sps信息中的帧率,以及帧计数frame_count即可计算出PTS。此方法需要做几帧缓存(一般缓存一个group的长度)。
I P B B I P B B I P B ... 帧类型
1 2 3 4 5 6 7 8 9 10 11 ... 第几帧
1 4 2 3 5 8 6 7 9 12 10 ... 帧显示顺序
一个I帧与下一个I帧之间,是一个group。
从上图可见,P类型的帧的显示顺序,是排在后面最后一个B帧之后。
所以要获取第7帧的pts,起码要知道他下一帧的类型,才能得知他的显示顺序。
第8帧的pts=1000(毫秒)
7(帧显示顺序)
帧率
方法二、每一个slice的信息里面,都记录有pic_order_cnt_lsb,当前帧在这个group中的显示顺序。通过这个pic_order_cnt_lsb,可以直接计算出当前帧的PTS。此方法不需要做帧缓存。
计算公式:
pts=1000(i_frame_counter + pic_order_cnt_lsb)(time_scale/num_units_in_tick)
i_frame_counter是最近一次I帧位置的帧序,通过I帧计数+当前group中的帧序,得到帧实际显示序列位置,乘上帧率,再乘上1000(毫秒)的base_clock(基本时钟频率),得到PTS。
I P B B I P B B I P B ... 帧类型
1 2 3 4 5 6 7 8 9 10 11 ... 第几帧
1 4 2 3 5 8 6 7 9 12 10 ... 帧显示顺序
0 6 2 4 0 6 2 4 0 6 2 ... pic_order_cnt_lsb

细心一点可以注意到,在上图,slice里面的pic_order_cnt_lsb是以2进行递增。
通常H264里面的sps中记录的帧率,也是实际帧率的2倍time_scale/num_units_in_tick=fps*2

因此,实际的计算公式应该是这样
pts=1000(i_frame_counter2+pic_order_cnt_lsb)* (time_scale/num_units_in_tick)
或者是
pts=1000(i_frame_counter+pic_order_cnt_lsb/2) (time_scale/num_units_in_tick/2)
所以,第11帧的pts应该是这么计算
1000(92+2)*(time_scale/num_units_in_tick)
结束语:
这里pts的base_clock都是按照1000(毫秒)计算,如果复用到ts里,base_clock是90k,所以还应该再乘以90。

题外话:关于H264中sps里面记录的帧率是实际帧率的2倍,包括slice里面的pic_order_cnt_lsb也是2倍递增,我推测可能是编码按照分场(顶场、底场)编码所致。另外我注意到sps信息中的offset_for_top_to_bottom_field字段,从命名上,貌似是可以用来标记是否逐场,还是分奇偶场编码。以上都属猜测,有请高人解惑。 Orz

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容