http://www.rosoo.net/a/201107/14663.html
一般fps在代码里这样表示
Fps = den/num
如果den = 15,num=1,则fps = 15。
如果帧率固定,pts*fps 就表示当前是第几帧。
当输入视频流的帧率不固定,如rmvb ,而输出视频流的帧率固定,ffmpeg作如下处理(参考ffmpeg代码版本0.6.1):
1、 记录和输出视频流ost相对应的输入视频流ist,变量为ost->sync_ist。这是在av_transcode函数进行输出流初始化时进行的。代码分别为:
- if(ist->discard&&ist->st->discard!=AVDISCARD_ALL&&!skip&&
- ist->st->codec->codec_type==ost->st->codec->codec_type){
- if(best_nb_frames<ist->st->codec_info_nb_frames){
- best_nb_frames=ist->st->codec_info_nb_frames;
- ost->source_index=j;
- found=1;
- }
- }
- if(!found){
- if(!opt_programid){
- /*tryagainandreuseexistingstream*/
- for(j=0;j<nb_istreams;j++){
- ist=ist_table[j];
- if(ist->st->codec->codec_type==ost->st->codec->codec_type
- &&ist->st->discard!=AVDISCARD_ALL){
- ost->source_index=j;
- found=1;
- }
- }
- }
- ist=ist_table[ost->source_index];
- ist->discard=0;
- ost->sync_ist=(nb_stream_maps>0)?
- ist_table[file_table[stream_maps[n].sync_file_index].ist_index+
- stream_maps[n].sync_stream_index]:ist;
2、 记录输出视频流ost的时间戳。输出为固定帧率,故可以简化为记录帧数,变量为ost->sync_opts。
3、 将ost对应的ist的pts转换成固定帧率的帧数形式。代码为
- sync_ipts=get_sync_ipts(ost)/av_q2d(enc->time_base);
get_sync_ipts计算ost对应的ist的pts,
av_q2d返回enc->time_base.num/ enc->time_base.den,即1/fps.
4、 将sync_ipts和ost->sync_opts进行求差。
- doublevdelta=sync_ipts-ost->sync_opts;
5、 根据vdelta来判断不同的情况。
l 情况一:Vdelta<-1.1,表示当前输入帧的播放时间在当前输出帧的前一帧之前,故舍弃该帧,nb_frames = 0。
l 情况二: (video_sync_method == 2 || (video_sync_method<0 && (s->oformat->flags & AVFMT_VARIABLE_FPS))){
if(vdelta<=-0.6){
nb_frames=0;
}else if(vdelta>0.6)
ost->sync_opts= lrintf(sync_ipts);}
这里video_sync_method==2 和video_sync_method < 0 表示什么意义,不是很清楚。貌似ffmpeg里video_sync_method一直设为-1。AVFMT_VARIABLE_FPS应该是变帧率的意 思。这种情况下,vdelta<=0.6,表示位于当前帧之前,也舍弃该帧,nb_frames = 0;vdelta>0.6表示位于当前帧之后,直接把该帧的时间戳作为输出的时间出来输出该帧;0.6<vdelta<=0.6时,不 做任何处理,nb_frames 根据默认值为1。
l 情况三:vdelta > 1.1
此时nb_frames = lrintf(vdelta),需要做插帧操作。
Ffmpeg的插帧操作,貌似是把当前输出帧重复输出nb_frames次。
- AVFrame*old_frame=enc->coded_frame;
- enc->coded_frame=dec->coded_frame;//FIXME/XXXremovethishack
- pkt.data=(uint8_t*)final_picture;
- pkt.size=sizeof(AVPicture);
- pkt.pts=av_rescale_q(ost->sync_opts,enc->time_base,ost->st->time_base);
- pkt.flags|=AV_PKT_FLAG_KEY;
- write_frame(s,&pkt,ost->st->codec,bitstream_filters[ost->file_index][pkt.stream_index]);
- enc->coded_frame=old_frame;
输出的数据在pkt.data里,final_picture即为经过处理的输入Pic。
6、输出视频流的帧率,是从输入视频流的包头数据中获得的。Rmvb的vedio MDPR块里,保存有fps和fps2信息。Ffmpeg取fps作为帧率,fps2丢弃了。Fps2有什么用,还不清楚。介绍rmvb格式的文章里也没有看到过关于fps的任何介绍。