實習工作記錄(2018.11-2019.2)

實習工作記錄

  • Android下ffmpeg+x264+fdk-aac軟解碼demo

功能描述:Android下獲取攝像頭1080P的YV12格式視頻編碼爲h264格式視頻保存,同時獲取PCM格式音頻數據編碼爲AAC格式音頻保存
重點:控制編碼時間不超過33ms
編碼時間優化過程:
首先在native層使用ffmpeg的編碼器接口調用x264庫
關鍵的參數設置爲

pCodecCtx->thread_count = 4 ;//設置開啓線程數(測試手機的cpu核數)
av_dict_set(&param, "preset", "ultrafast", 0);  //有ultrafast、superfast、veryfast、fast、、medium、slow、slower、veryslow的選項,影響編碼速度和質量
av_dict_set(&param, "tune", "zerolatency", 0); //有film 、animation、grain、stillimage、psnr、ssim、fastdecode、zerolatency的選項,從左到右編碼複雜度依次遞減,質量依次遞減,實時編碼必須設置zerolatency,表示零延遲輸出當前編碼幀

但是在這個參數設置下,編碼時間爲80ms一幀,並會逐漸增長,達不到要求
分析編碼處理時間包括:

  1. 將YV21數據轉換成YUV420P的時間
  2. ffmpeg與X264編碼器之間的參數傳遞和函數調用
  3. x264編碼器編碼的時間

數據格式在1080P下的轉換時間在10毫秒左右,爲了排除ffmpeg的影響,我對x264庫相同設置下的編碼時間進行了測試,單獨編譯了x264庫,配置了AS,在native層重寫了一個調用264庫的類,封裝好給java層調用,編碼速度得到提升,但還是逐漸變慢,分析應該是由於編碼對於CPU的需求比較高,但編碼線程並沒有得到很好的調度,所以在java層採用android.os.Process類中設置優先級的函數來對編碼線程進行調度優化,結果就是,直接使用x264工程加上調度優化可以滿足需求,也就是說x264編碼器在設置正確的情況下的速度是可以滿足要求的

接下來研究爲什麼在使用ffmpeg調用x264庫時同樣的設置起不了作用,對log和源碼進行分析之後發現,雖然設置了幀並行編碼線程數,但是並沒有起作用,也就是說並行編碼沒起作用,這是由於ffmpeg的參數設置並不是與x264的參數完全一一對應,要加上以下設置(表明並行類型是幀並行),結果就與直接應用x264無差異了

pCodecCtx->thread_type = FF_THREAD_FRAME;

需要注意的問題:
1 編譯x264和fdk-aac庫的時候可能會出現找不到庫的問題,這是由於路徑設置可能存在問題
2 fdk-aac庫在使用ffmpeg調用時,可能會報錯,這是使用了根據id尋找編碼器的函數造成的,由於fdk-aac的id與ffmpeg內置aac格式的音頻編碼器的id相同,所以應使用編碼器name尋找(avcodec_find_encoder_by_name(“libfdk_aac”))

  • 研究如何給ffmpeg添加自定義的編碼器
    在這裏插入圖片描述
  • 編寫Android下MediaCodec硬解碼類
    描述:實現三個接口,init、encode、release,encode實現YUV420P到h264同步編碼,爲了熟悉Android硬解碼功能
  • 優化首幀時間
    描述:線上代碼存在首幀硬編碼時間過長問題(從開始獲取圖像至返回編碼後的首幀時間400-500ms)
    首幀過慢原因
    線上的硬編碼代碼邏輯是,每次獲取到相機返回的圖像後調用encodevideofrombuffer()進行此幀的編碼並返回編碼後的幀
    核心函數encodevideofrombuffer()中的邏輯是獲取編碼器的的可用buffer將YUV數據寫入,並調用dequeueOutputBuffer( bufferInfo, TIMEOUT_USEC)取出編碼後的幀

有兩部分原因導致首幀時間長
1 初始化硬解碼器的時機不對,應該儘量將初始化代碼提前

2 TIMEOUT_USEC設置過小,編碼未完成導致超時返回,只能放棄此次取數據,等到下次相機返回圖像時再取出此幀,也由於android的硬編碼器規定要先輸出一個配置幀,所以一般要等到第二、三幀時才能獲取到首幀解碼後的數據,並且幀率越小,幀間間隔越大,拿到首幀的時間越長

優化過程
1、修改了init函數,將初始化時間提前到執行oncreate()
2、修改了TIMEOUT_USEC與邏輯,使得可在第一次調用encodevideofrombuffer()時就返回解碼後的首幀
優化結果
從獲取到相機圖像到獲取到解碼後的首幀的時間縮短至40ms左右

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