1. 程式人生 > >ffmpeg轉碼時對編位元速率和固定位元速率的處理

ffmpeg轉碼時對編位元速率和固定位元速率的處理

一般fps程式碼裡這樣表示

Fps = den/num

如果den = 15num=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對應的istpts轉換成固定幀率的幀數形式。程式碼為

sync_ipts = get_sync_ipts(ost) / av_q2d(enc->time_base);

get_sync_ipts計算ost對應的istpts,

av_q2d返回enc->time_base.num/ enc->time_base.den,1/fps.

4、sync_iptsost->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 表示什麼意義,不是很清楚。貌似ffmpegvideo_sync_method一直設為-1AVFMT_VARIABLE_FPS應該是變幀率的意思。這種情況下,vdelta<=0.6,表示位於當前幀之前,也捨棄該幀,nb_frames = 0vdelta>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, b

itstream_filters[ost->file_index][pkt.stream_index]);

enc->coded_frame = old_frame;

輸出的資料在pkt.data裡,final_picture即為經過處理的輸入Pic

6、輸出視訊流的幀率,是從輸入視訊流的包頭資料中獲得的。Rmvbvedio MDPR塊裡,儲存有fpsfps2資訊。Ffmpegfps作為幀率,fps2丟棄了。Fps2有什麼用,還不清楚。介紹rmvb格式的文章裡也沒有看到過關於fps的任何介紹。