H264 Over RTP 和 音频采样率与时间戳的计算

H264 Over RTP 之 宝典 

http://blog.sina.com.cn/u/465bdf0b010002t1 (有点错误)

H264 Payload Format over RTP/RTCP,很久以前做的了,都快忘了,赶快复习一下吧,不然又还给...应该不是老师了吧,嘿嘿。

RTP包头还是贴一下吧,看起来方便:

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC  |M| PT                  | sequence number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp                                                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| contributing source (CSRC) identifiers                       |
| ....                                                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

这个就不多说了吧:)

接下来的就是H264的头了。

首先是NAL Unit Type,8个字节

+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type     |
+----------------------+

F:    定义为0

NRI(nal_ref_idc):00 不是用来构造I帧预测的参考帧。
                            非00  用来保持参考帧的完整性。

(什么东西啊,反正我是不明白,也用不到,下次去做编解码算了,看了N多概念,都不清楚,郁啊。)

Type(nal_unit_type): 如下表

Type | Packet Type | name                          

---------------------------------------------------------
0      | undefined -
1-23 | NAL unit     | Single NAL unit packet
24    | STAP-A      | Single-time aggregation packet
25    | STAP-B      | Single-time aggregation packet
26    | MTAP16     | Multi-time aggregation packet
27    | MTAP24     | Multi-time aggregation packet
28    | FU-A          | Fragmentation unit
29    | FU-B          | Fragmentation unit
30-31| undefined -

说明一下:

H264 over RTP基本上分三种类型:

1. Single NAL unit packet 也就是实际的NAL类型,可以理解为一个包就是一帧H264数据,这个在实际中是比较多的。

2. Aggregation packet 一包数据中含有多个H264帧。还可以细分,下面讲。

3. Fragmentation unit 一帧数据被分为多个RTP包,这也是很常见的,特别是对于关键帧。


细分一下Aggregation packet:

Aggregation packet 可以分为四种:

STAP-A 包内的帧含有相同的NALU-Time,没有DON

STAP-B 包内的帧含有相同的NALU-Time,有DON

MTAP16 包内的帧含有不同的NALU-Time,timestamp offset = 16

MTAP24 包内的帧含有不同的NALU-Time,timestamp offset = 24

实际用到的比较多的是1-23,STAP-A(24)和FU-A(28)其他类型的没有碰到过,就没有去研究了,当然我指的是客户端。你要做发送端的话,你自己订吧。

从RTP得到的数据是没有NAL头的,关于NAL头在RFC3984和ITUTH264文档里的意义好像不太一样,当初就是这个混淆了,折腾了半天。具体的忘了,我也懒得再去找了,下次再看到时候补上。实际应用就是要加上个H264 STREAM 的头

h264_stream_head  = 0x00,0x00,0x00,0x01 4字节

随后是NAL unit type ,这里指的是H264定义的NAL type,有点小差别,特别是在FU的时候,下面会讲。

Single NAL Unit Packet(1-23)

这个很简单了,一个包就是一帧数据。h264_stream_head + NAL_unit_type... 直接送去解码了。

 0 1  2  3 4 5 6 7  8 9  0 1 2 3 4  5 6 7 8  9 0 1 2 3 4  5 6 7  8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| type    |                                                                         |
+-+-+-+-+-+-+-|                                                                         |
| Bytes 2..n of a Single NAL unit                                                   |
|                                                                                              |    
|                                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                             :...OPTIONAL RTP padding           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 STAP-A(24)

 0 1  2  3 4 5 6 7  8 9  0 1 2 3 4  5 6 7 8  9 0 1 2 3 4  5 6 7  8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTP Header                                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|STAP-A NAL HDR| NALU 1 Size                                 | NALU 1 HDR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 1 Data                                                                            |
: :
+                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     | NALU 2 Size                                   | NALU 2 HDR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 2 Data |
: :
|                                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                             :...OPTIONAL RTP padding          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

看这个结构应该很清楚了,先是16位的长度,就可以得到地一帧,h264_stream_head + NALU 1 HDR...送去解码。再算下一帧。注意,不一定是32bit对齐的。

需要注意的这个NALU Size 是不包括他本身这2个字节。

 FU-A(28)

 0 1  2  3 4 5 6 7  8 9  0 1 2 3 4  5 6 7 8  9 0 1 2 3 4  5 6 7  8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator    | FU header          |                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                              |
|                                                                                              |
|                                    FU payload                                           |
|                                                                                               |
|                                             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                             :...            OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

FU Indicator

+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|     Type |
+----------------------+

FU Header

+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|     Type |
+----------------------+

S:1 表示是一帧的开始包

E:1 表示是一帧的结束包,和RTP marker位一致

R:0 必须

这里要注意一下,NAL unit type 必须自己拼装FU Indicator前四字节+ FU Header后四字节。也就是type字段是 FU header里的

nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)

等帧收齐了,加上H264_streaming_head + nal_unit_type....送去解码

有些已经记不清出了,都是从代码里推出来的,下次看的时候就该记下来。写的还真累啊,下班了,88

参考资料:

1. RFC3984 -- RTP Payload Format for H.264 Video

音频采样率与时间戳的计算

对于ffmpeg,时间戳间隔为:presentation_time  = frame_size/sample_rate;

frame_size:每帧数据对应的字节数

sample_rate:采样率,是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数

presentation_time:时间间隔,也就是该帧数据播放的时间长度,单位s,如果用毫秒为单位,乘上1000即可

                               presentation_time  = frame_size*1000/sample_rate;

例如:AAC每帧数据对应的字节数为1024,如果sample_rate==32K,对应的时间间隔为1024*1000/32000 = 32ms

mp3每帧数据对应的字节数为1152 ,如果smple_rate==8k,对应的时间间隔为1152*1000/8000 =    144ms

视频、音频打时间戳的方法

http://blog.csdn.net/wfqxx/article/details/5497138

1. 视频时间戳

     pts = inc++ *(1000/fps);  其中inc是一个静态的,初始值为0,每次打完时间戳inc加1.

    在ffmpeg,中的代码为

    pkt.pts= m_nVideoTimeStamp++ * (m_VCtx->time_base.num * 1000 / m_VCtx->time_base.den);

2. 音频时间戳

    pts = inc++ * (frame_size * 1000 / sample_rate)

   在ffmpeg中的代码为

   pkt.pts= m_nAudioTimeStamp++ * (m_ACtx->frame_size * 1000 / m_ACtx->sample_rate);

采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。

。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采样频率,还可以达到DVD的音质

对采样率为44.1kHz的AAC音频进行解码时,一帧的解码时间须控制在23.22毫秒内。

背景知识:

(一个AAC原始帧包含一段时间内1024个采样及相关数据)

分析:

1 AAC

音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率(单位为s)

一帧 1024个 sample。采样率 Samplerate 44100KHz,每秒44100个sample, 所以 根据公式   音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率

当前AAC一帧的播放时间是= 1024*1000000/44100= 22.32ms(单位为ms)

2 MP3

mp3 每帧均为1152个字节, 则:

frame_duration = 1152 * 1000000 / sample_rate

例如:sample_rate = 44100HZ时, 计算出的时长为26.122ms,这就是经常听到的mp3每帧播放时间固定为26ms的由来。

音视频同步(播放)原理

每一帧音频或视频都有一个持续时间:duration:
采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。
。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、

11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采样频率,还可以达到DVD的音质
对采样率为44.1kHz的AAC音频进行解码时,一帧的解码时间须控制在23.22毫秒内。
背景知识:
(一个AAC原始帧包含一段时间内1024个采样及相关数据)
分析:
1) AAC
音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率(单位为s)
一帧 1024个 sample。采样率 Samplerate 44100KHz,每秒44100个sample, 所以根据公式   音频帧的播放时间=一个AAC帧对应的采样样本的个数/采样频率
当前AAC一帧的播放时间是= 1024*1000000/44100= 22.32ms(单位为ms)
2) MP3
mp3 每帧均为1152个字节, 则:
frame_duration = 1152 * 1000000 / sample_rate
例如:sample_rate = 44100HZ时,计算出的时长为26.122ms,这就是经常听到的mp3每帧播放时间固定为26ms的由来。
3)H264
视频的播放时间跟帧率有关 frame_duration = 1000/fps
例如:fps = 25.00 ,计算出来的时常为40ms,这就是同行所说的40ms一帧视频数据。

理论上的音视频(播放)同步是这样的:
由此得到了每一帧数据的持续时间,音视频交叉存储在容器中:一个时间轴:
时间轴:0   22.32   40     44.62    66.96    80     89.16      111.48    120       ................
音   频 :0   22.32            44.62    66.96             89.16      111.48                ................
视   频 :0              40                              80                                   120       ................
即视频的持续时间相加 和音频的持续时间相加作比较,谁小写入哪个。

但实际情况(播放)是不成立的

1:首先解决一个问题

为什么不 音频播音频的 视频播视频的 即上面的 到 第22.32ms播一帧音频 ,到40ms播一帧视频。

因为这个22.32ms 或40ms是算不准的或者说和声卡播的时间是不一样的。这里就需要知道声卡播一帧/或者说播放一个buf音频需要多长时间。

2:声卡每次播一个采样点 而不是一帧。声音当一个采样点丢失了都可以听出来,视频则不然。

3:音视频同步方式:1----回调方式

假设声卡有两块缓存都是存放要播放的声音pcm的 一直在播放"B"buf 首先确定几点

(1)buf大小是固定的这样播放一个buf的时间就是固定的,假设30ms;

(2)当buf“B”播放完毕即buf用完,再播放buf“A",保证音频pcm一直都连续

(3)当一个buf播放完毕,那说明系统(声卡)过了30ms, 这时候有可能真正的时间过了40ms(这里不用关心),这里则通过回调得到一次时间30ms;

(4)再去用视频对应音频的30ms,这时候的时间就是准确的:

时间轴:0                    30                         60                         90                                        120       ................
音   频 :0     22.32                 44.62                 66.96     89.16                       111.48                     ................
视   频 :0                          40                                    80                                                  120       ................

(5)这里有个问题就是 视频中 30ms 到40ms 这中间的10ms是怎么算出来的,这个是不用关心的,因为人的眼睛10ms是看不出来的,

即当音频的30ms一次回调时,就可以播放第二帧视频,如上图

第一次回调(30ms)---播(40ms)视频,

第一次回调(60ms)---播(80ms)视频,

第一次回调(90ms)---不播视频,

第一次回调(120ms)---播(120ms)视频。

4:音视频同步方式:1----阻塞方式

还是看上面的图

(1)buf"B"一直在播放,传入buf"A"的外部buf把数据给buf"A"后 不立即返回,等到buf"B"播放完成再返回,

这时从传入到经过阻塞出来就是一个buf的时间例如上面的30ms。

(2)然后buf"A"一直在播放,传入buf"B"的外部buf把数据给buf"B"后 不立即返回,等到buf"A"播放完成再返回,

这时从传入到经过阻塞出来就是一个buf的时间例如上面的30ms。

(3)循环上面(1)(2),即得到了如回调方式同样的那个30ms时间。下面和回调方式一样,见回调方式(4)(5)。

转自   http://blog.csdn.net/zhuweigangzwg/article/details/25815851

猜你喜欢

转载自blog.csdn.net/hyl999/article/details/108829156