ffmpeg使用問題記錄

1.正常情況下一個封裝好的視頻文件,例如mp4或者mkv文件,其音頻數據是經過了aac編碼器編碼的(如果是其他的編碼器,那麼提取的數據格式要和編碼器一致),其視頻數據是經過了h264編碼器編碼的,這時候如果你僅僅是提取出數據的話,音頻文件格式要是AAC格式,比如test.aac,視頻文件要是test.h264格式才行。如果要換成其他格式就必須經過解碼,然後編碼,再封裝。

 

2.使用ffplay播放yuv和pcm數據的時候,要注意輸入對應的參數,比如yuv數據的話,使用ffplay命令也要把視頻的分辨率輸入進去,pcm數據的時候也需要把採樣率、通道數、存儲數據的格式S16LE等這些參數輸入進去才能正常播放。

 

3.ffmpeg中濾鏡的使用一般是對解碼後的數據進行處理然後再編碼的,不可能直接對編碼的數據進行處理。所以如果要使用濾鏡,是一定要進行解碼,然後再編碼操作的。使用命令行的時候也要記得用設定好編碼器。

 

4.用MKV轉avi格式報錯,例如ffmpeg.exe -i out.mkv -vcodec copy -acodec copy out1111.avi執行失敗,是因爲MKV格式中的音頻是aac,視頻是H264,但是avi格式中的視頻格式是MPEG-4,音頻格式是MP3,所以當你用原來的編解碼器肯定是會報錯的。正確命令行應該是ffmpeg.exe -i out.mkv -vcodec mpeg4 -acodec libmp3lame out333.avi或者ffmpeg.exe -i out.mkv out222.avi(ffmpeg默認會選擇對應的編解碼器)

 

5.時間基理解:每個視頻文件的時間基都有可能是不一樣的,並且在使用api編碼過程中最好都要使用av_rescale_q_rnd來把輸入文件的時間基轉換成輸出文件的時間基,我在有的項目中有過沒有調用av_rescale_q_rnd也能使用的情況,也許是當時項目中沒有這塊要求吧,建議自己以後在使用av_interleaved_write_frame寫入文件之前,最好用av_rescale_q_rnd轉換下再寫入。而輸入的參數中,其中一個就是pts(視頻渲染時間戳)。

 

6.gop_size參數作用:這個值是設置GOP用的。GOP:關鍵幀的週期,也就是兩個關鍵幀之間的距離,一個幀組的最大幀數,一般而言,每一秒視頻至少需要使用 1 個關鍵幀。增加關鍵幀個數可改善質量,但是同時增加帶寬和網絡負載。在一個GOP中,P、B幀是由I幀預測得到的,當I幀的圖像質量比較差時,會影響到一個GOP中後續P、B幀的圖像質量,直到下一個GOP 開始纔有可能得以恢復,所以GOP值也不宜設置過大。如果設置gop_size小的話,那麼碼率就大了,設置大的話,碼率會減小,但是一旦丟失關鍵幀,那麼只有等下一組GOP幀過來才能恢復。

舉個例子,假如你gop_size = 10;那麼就表示10幀裏有一個關鍵幀,那麼下一個10幀中才有一個關鍵幀。

 

7.使用ffmpeg編碼或者轉碼後生成的視頻文件很模糊,視頻質量很差。決定因素很多,這裏先記錄下我自己發現的4點因素:

1.通過設置編碼速度來優化視頻模糊,代碼如下:

AVDictionary *options = nullptr;
av_dict_set(&options, "preset", "veryslow", 0);
result = avcodec_open2(outCodecContext, outEncoder, &options);

設置preset的參數值爲veryslow或者更慢的參數來優化模糊。但是這種情況不能完全使生成的文件和原始文件一樣清晰。

2.通過第一步知道不能完全和原始文件一樣清晰,那麼我們需要設置編碼器上下文中的me_subpel_quality,如下:

	AVCodecContext* outCodecContext = outStream->codec;
    outCodecContext->me_subpel_quality = 7;

個人測試感覺在設置了第一步的情況下,又添加了這步me_subpel_quality設置,效果沒有更進一步的提高。

3.後來在調試參數的時候發現把碼率設置很高的話,畫面清晰度就好很多了:

outCodecContext->bit_rate = 1000000;//原本正常的一般都是40 0000,但是這裏我設置成100 0000甚至200 0000後畫面清晰的不得了

但是生成的視頻文件大概有3M多,原始視頻yuv文件是300多M,所以如果是視頻流媒體傳輸的話,設置到這裏就差不多了。

4.修改qmin,qmax參數後,視頻文件和原始文件一樣清晰,代碼如下:

		outCodecContext->qmin = 0;
		outCodecContext->qmax = 0;

但是生成的文件相對來說挺大的,將近60M(原始yuv文件是300多M)所以如果是用於視頻傳輸不建議這麼設置,如果僅僅是文件之間的相互轉換可以這樣設置。

 

8.關於使用ffmpeg提供的api如何設置pts問題,目前我自己總結出來有兩種方法:

A)定義一個long long型變量,每次把這個變量的值賦值給編碼後的packet.pts,然後這個變量要自加一次。這種方式主要在於packet中pts的值爲0的情況下,一般原始yuv數據中會有這種情況,輸入源是攝像頭或者原始yuv數據,適用場景適合於推流,但是值得注意的是如果推流是24小時不間斷的一直推流,那麼就要考慮到long long型變量溢出的問題了。

B)還有一種是通過av_rescale_q_rnd來進行轉換的,這種適合場景適合輸入源是視頻封裝格式,本身就帶有時間基的。原因是這種情況輸入源是帶有pts的,並且帶有時間基。

 

9.今天把h264視頻文件和MP3格式的音頻文件合併mkv封裝格式的視頻文件時,發現設置音頻編碼器爲AV_CODEC_ID_AAC時,輸出文件用播放器黑屏並且不會顯示視頻,但是音頻時正常的。如果設置成AV_CODEC_ID_MP3就正常。不知道是不是是不是因爲輸入的是MP3格式的音頻文件。這裏特此記錄

 

10.實際工作用有時候調接口api接口返回錯誤,目前我瞭解到的情況情況主要有兩種:

A)你在使用這些api接口的時候,沒有調用ffmpeg的註冊函數,比如說av_register什麼之類的。

B)你傳入的參數有問題。

 

11.視頻畫面模糊、馬賽克等可以試着提高碼率來處理。

 

12.使用av_find_best_stream函數獲取流信息失敗的原因之一:

需要先調用avformat_find_stream_info函數,然後調用av_find_best_stream函數纔不會失敗。

13.FFMPEG使用第三方編碼數據推流畫面花屏卡着不動問題處理:視頻幀數據用硬件編碼輸出,僅僅使用FFMPEG將硬件編碼出的數據推流RTSP數據後嚴重花屏且畫面卡住不動

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章