http://blog.csdn.net/zww_sap111/article/details/8766514
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) {
- /* try again and reuse existing stream */
- 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進行求差。
- double vdelta = 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/XXX remove this hack
- 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的任何介紹。
(fanner01)