雷神muxer中手动写pts的部分很不理解。网上也找不到解释,研究半天,感觉理解的差不多了,特此记录。如果有误,请不吝赐教。
//FIX:No PTS (Example: Raw H.264)
//Simple Write PTS
if (pkt.pts == AV_NOPTS_VALUE) {
//Write PTS
AVRational time_base1 = in_stream->time_base;
//Duration between 2 frames (us)
int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
//Parameters
pkt.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);
pkt.dts = pkt.pts;
pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);
frame_index++;
}
首先需要先对PTS/DPS有一定的了解
PTS/DPS相关一
PTS/DPS相关二
PTS/DPS相关三
我一开始的疑问是为什么要这样写,这样写的依据是什么。
首先理解:
真正的显示时间的意思是这一帧图像在视频中的显示时刻,设置fps=25,那么第一帧图像的第0s时刻显示,第二帧图像在第0.04s时刻显示,第三帧图像在第0.08s时刻显示。
pts和time_base是成对变化的
但是不管pts和time_base怎么变化,pts * av_q2d(time_base)
的真正显示时间是不变的
timestamp(秒) = pts * av_q2d(time_base)
其中 timestamp(秒) 即为真正的显示时间。所以,
真正的显示时间(秒)= pts * av_q2d(time_base) 。所以,
pts = 真正的显示时间(秒)/av_q2d(time_base) 。
#define AV_TIME_BASE 1000000(us)
通过帧率可以计算真正的显示时间,此时的时间基是{1,AV_TIME_BASE}。
假如裸H264流的帧率为25帧,即tbr=25。那么每得到一帧的图像就可以知道这帧图像的帧率时间基的真正的显示时间。第一帧真正的显示时间是1/25(秒)即pts = 4000,第二帧真正的显示时间是2/25(秒)即pts = 8000,第三帧真正的显示时间是3/25(秒)即 pts = 12000,等以此类推。
此时真正的显示时间的时间基是{1,AV_TIME_BASE},这样就可以计算时间基是{1,AV_TIME_BASE} 的pts。接着再转换成输入流的时间基即in_stream->time_base。
将雷神的代码改成下边这样,思路更圆滑一些:
if (pkt.pts == AV_NOPTS_VALUE) {
//内部时间基
AVRational temp = {1,AV_TIME_BASE};
//以内部时间基的一帧显示长度,in_duration 单位us
double in_duration = (double) 1/ av_q2d(in_stream->r_frame_rate);
//以{1,AV_TIME_BASE}为时间基的pts,
//frame_index*in_duration真正的显示时间
pFrame->pts = (double)(frame_index*in_duration)/av_q2d(temp);
//从时间基{1,AV_TIME_BASE} 转换成 in_stream->time_base的时间基
pFrame->pts = av_rescale_q_rnd(pFrame->pts , temp, in_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
frame_index++;
}