Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7894066
  • 博文数量: 701
  • 博客积分: 2150
  • 博客等级: 上尉
  • 技术积分: 13233
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-29 16:28
个人简介

天行健,君子以自强不息!

文章分类

全部博文(701)

文章存档

2019年(2)

2018年(12)

2017年(76)

2016年(120)

2015年(178)

2014年(129)

2013年(123)

2012年(61)

分类: 架构设计与优化

2017-11-11 16:47:43

一、打时间戳方法

1.1 背景知识

1.1.1 采样频率:
是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。
正常人听觉的频率范围大约在20Hz~20kHz之间.
根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。
常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,
如果采用更高的采样频率,还可以达到DVD的音质.




1.1.2 音频帧
一个AAC音频帧包含以采样率为基准的1024个采样点数据,及其它相关数据。
如: AAC
音频帧的播放时间  =  一个音频帧对应的采样样本的个数 /  采样频率(单位为s)
AAC的一帧是 1024个采样点,
在采样率为44100Hz时(即每秒44100个sample), 所以 根据公式   
当前AAC一帧的播放时间是 = 1024* (1000000/44100) = 22.32ms (单位为ms)


再如: MP3
mp3 每帧均为1152个字节, 则:
frame_duration = 1152 * 1000000 / sample_rate
例如:sample_rate = 44100HZ时, 计算出的时长为26.122ms,
这就是经常听到的mp3每帧播放时间固定为26ms的由来。




1.2 固定帧率

1.2.1 视频时间戳:
    pts = inc++ *(1000/fps);  
其中:
inc  , 是视频帧序号,初始值为0,每次打完时间戳inc加1.
1000 , 是1000 毫秒
fps  , 视频帧率,换个方式理解的意思是视频采样率,如 25fps 表示 每秒采样25帧;
(1000/fps), 表示每帧,在当前设置的帧率下应该持续显示的毫秒数。如 1000 msec /25 fps = 40 msec;  

在ffmpeg中的代码为:
    pkt.pts = m_nVideoTimeStamp++ * (1000 *  m_VCtx->time_base.num / m_VCtx->time_base.den);
其中:
    m_VCtx->time_base.num/m_VCtx->time_base.den, 时针基,
   即将1毫秒再切分成多少等份,以提高时钟计算的精度。
   如, mpeg-ts是90kHz, FLV是1KHz,FFmpeg为了提高精度,用的是1MHz, 
   所以ffmpeg中,在接收输入帧时,要将换算成ffmpeg的时钟基表示的时间戳;输出时,换算成输出格式的时针基表示的时间戳。
    (1000 *  m_VCtx->time_base.num / m_VCtx->time_base.den), 表示以time_base时针基计算的每帧应该持续显示的时间。

以 H264 为例:
视频的播放时间跟帧率有关 frame_duration = 1000/fps
例如:fps = 25.00 ,计算出来的时常为40ms,这就是同行所说的40ms一帧视频数据。

1.2.2 音频时间戳:
    pts = inc++ * ( frame_size / sample_rate);
其中:
inc  , 是音频帧序号,初始值为0,每次打完时间戳inc加1.
    frame_size,  每帧大小,AAC的一帧包含1024个采样点
sample_rate, 采样率,如 8kHz, 11.025kHz, 22.05kHz, 16kHz, 44.1kHz等,表示每秒进行的采样次数,一次一个采样点;
(frame_size / sample_rate), 表示每帧的持续时间,以AAC为例:
         AAC一帧的播放时间是= 1024*(1000000微秒/44100)= 23219us =  23.22ms
    音频帧率 =    采样率 / 每帧的大小;  如 AAC 在16kHz采样率下:
            帧率 =  16 000 / 1024 = 15.625 fps
在ffmpeg中的代码为
   pkt.pts= m_nAudioTimeStamp++ * (m_ACtx->frame_size * 1000 / m_ACtx->sample_rate);


1.3 可变帧率

有很多的采集卡,摄像头,在做采集的时候,明明设置的25FPS,
但实际采集数据回调过来,发现并不是40毫秒的间隔,而是50,60,甚至100不等的时间间隔。
这就给编码后打时间戳带来很大的困难。


在libav里,我们的默认编码参数都是:
   ptAvEncoder->ptAvStreamVideo->codec->time_base.den = s32Fps;
   ptAvEncoder->ptAvStreamVideo->codec->time_base.num = 1;
这样在编码后的时间戳以1递增,只适合于固定帧率。


我们来改一下:
   ptAvEncoder->ptAvStreamVideo->codec->time_base.den = s32Fps * 1000;
   ptAvEncoder->ptAvStreamVideo->codec->time_base.num = 1* 1000;


这样就把时间戳的scale变成了毫秒,就可以以毫秒为单位进行计算了,如下:
  tAvPacket.pts = ((s64)u32TimeStamp * (s64)s32Fps);
其中:
  u32TimeStamp, 是从开始记录的时间差值,以毫秒为单位;
  s32Fps,  是帧率。


1.3.1 对于MP4 
对于音频,mp4文件默认是采样率为tick的,时间戳计算为:
tAvPacket.pts = (AvEncoderAudioInSizeGet(hHandle) * ( (s64)(u32TimeStamp)) / 
                (AvEncoderAudioInSizeGet(hHandle) * 1000 / ptAvEncoder->ptAvStreamAudio->codec->sample_rate);
其中:
   AvEncoderAudioInSizeGet(hHandle),  每次编码器需要的PCM数据长度。
   u32TimeStamp,  是从开始记录的时间差值,以毫秒为单位。
   ptAvEncoder->ptAvStreamAudio->codec->sample_rate,  是PCM采样率,代表一秒的数据量。
因为乘以了1000,所以也化成了毫秒单位。


对于mp4,  视频直接用绝对时间. 


1.3.2  对于RTMP 
对于rtmp,音频和视频都是用绝对时间, 
视频是毫秒计算,音频也换算成毫秒计算


阅读(5307) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~