ffmpeg轉碼時對變幀率和固定幀率的處理


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函數進行輸出流初始化時進行的。代碼分別為:

  1. if (ist->discard && ist->st->discard != AVDISCARD_ALL && !skip && 
  2.   ist->st->codec->codec_type == ost->st->codec->codec_type) { 
  3.     if(best_nb_frames < ist->st->codec_info_nb_frames){ 
  4.       best_nb_frames= ist->st->codec_info_nb_frames; 
  5.       ost->source_index = j; 
  6.       found = 1; 
  7.     } 
  8.   } 
  9.   if (!found) { 
  10.    if(! opt_programid) { 
  11.       /* try again and reuse existing stream */ 
  12.       for(j=0;j<nb_istreams;j++) { 
  13.       ist = ist_table[j]; 
  14.       if (   ist->st->codec->codec_type == ost->st->codec->codec_type 
  15.    && ist->st->discard != AVDISCARD_ALL) { 
  16.       ost->source_index = j; 
  17.       found = 1; 
  18.       } 
  19.       } 
  20.       } 
  21.       ist = ist_table[ost->source_index]; 
  22.       ist->discard = 0; 
  23.       ost->sync_ist = (nb_stream_maps > 0) ? 
  24. ist_table[file_table[stream_maps[n].sync_file_index].ist_index + 
  25.           stream_maps[n].sync_stream_index] : ist; 

2、  記錄輸出視頻流ost的時間戳。輸出為固定幀率,故可以簡化為記錄幀數,變量為ost->sync_opts。

3、  將ost對應的ist的pts轉換成固定幀率的幀數形式。代碼為

  1. 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進行求差。

  1. 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次。

  1. AVFrame* old_frame = enc->coded_frame; 
  2. enc->coded_frame = dec->coded_frame; //FIXME/XXX remove this hack 
  3. pkt.data= (uint8_t *)final_picture; 
  4. pkt.size=  sizeof(AVPicture); 
  5. pkt.pts= av_rescale_q(ost->sync_opts, enc->time_base, ost->st->time_base); 
  6. pkt.flags |= AV_PKT_FLAG_KEY; 
  7. write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]); 
  8. enc->coded_frame = old_frame; 

輸出的數據在pkt.data里,final_picture即為經過處理的輸入Pic。

6、輸出視頻流的幀率,是從輸入視頻流的包頭數據中獲得的。Rmvb的vedio MDPR塊里,保存有fps和fps2信息。Ffmpeg取fps作為幀率,fps2丟棄了。Fps2有什么用,還不清楚。介紹rmvb格式的文章里也沒有看到過關於fps的任何介紹。

(fanner01)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM