Android硬件編解碼與軟件編解碼


       最近做了一個android項目用到編解碼功能。大概需求是:通過攝像頭拍攝一段視頻,然后抽幀,生成一個短視頻,以及倒序視頻,剛開始直接用 H.264 編碼格式,沒有使用MP4容器封裝。做了這些功能后,反而覺得使用MP4格式更加兼容各機型,減少BUG出現。舉個明顯例子:在Android硬編的時候,常常會用到 MediaCodec和MediaExtractor 相結合。但是,如果你用的 H.264 裸視頻文件,MediaExtractor 的 setSource 函數會報異常,它在某些機型(如魅族Note2,系統是5.1)無法解析該視頻文件。
      得到大概的需求后,最初我們使用FFmpeg來做視頻編解碼,所謂軟件編解碼。由於在處理的過程中速率太慢,且需要在解碼后快速展示,所以該方案無法達到我們的預想效果(一個FFmpeg視頻解碼,並保存為jpeg例子: https://github.com/xiaoxiaoqingyi/ffmpeg-android-video-decoder)。但其也有一些優點,比如在兼容方面,顏色轉換方面都做得很好,畢竟不是硬件編解碼(國內這么多機型,你懂的),其次FFmpeg能輸出指定幀,而Android硬解(MediaCodec)不能輸出指定幀,需要輸入好幾幀到解碼器,才能解碼出一幀。目前我還是沒有找到輸入一幀解出一幀的方案,哪位大神知道的,可以指導指導。
       在軟件編解碼不太適合的情況下,就只能考慮用硬件編解碼了(MediaCodec)。在前些日子,我參加了騰訊2017LIVE 直播開發者大會,了解到,現在的直播已經大部分使用硬件來編解碼了。剛說了,有些機型不能使用MediaExtractor來解析 h.264文件,為了兼容大部分的機型,需要自己來解析,通過分析h.264文件的每一個字節區分每一幀位置且是什么類型幀。實現該需求,首先在從攝像頭獲取的數據,如果使用 Camera,一般設置為NV21格式, 但有些人使用Camera2,設置的格式是IMAGE。不管是哪種格式,最終都需要轉換成yuv420sp或yuv420p(注意:在轉碼時候,最好使用jni,用C/C++來轉格式,效率會高很多倍),才能供MediaCodec編碼,然后保存h.264文件。在創建MediaCodec實例化的時候,除了設置必須參數外,也要注意一些地方,比如,選擇哪種編碼器,一般情況會選擇如下:
 MediaCodec.createEncoderByType("video/avc");
這看上去其實沒什么問題,大概原理就是獲取最優的Encoder,獲取Android系統中編碼器注冊表最前的一個,一般都是硬件解碼(MediaCodec也能調用軟件編解碼)。這樣創建編碼器其實不太靠譜,雖然官網也是這么推薦,但是在國內眾多的Android機型中,有些手機就會出問題,有的編碼出現藍屏,有些直接就閃退了。有個國外的例子,大概的意思就是先獲取 "video/avc" 類型的編碼器,然后通過 try catch 一個個試驗,如果沒問題,就選用這個編碼器。源碼: https://github.com/ldm520/android_mediacodec_rtsp_h264
還有一個問題就是在設置 I 幀間隔的時候,有些手機不起作用,如下設置:
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, interval);
 
針對這種情況,需要使用另外一種設置I幀的方式,強制設置:
 
Bundle params = new Bundle();
params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
mMediaCodec.setParameters(params);
 
在編解碼時,當把所有的數據都輸入編解碼器的時候,要記得輸入結束符,編解碼器才會輸出所有的幀。
 
    還有一個抽幀問題,如果使用MediaCodec來抽幀,生成一個新的視頻。是否可以直接把H.264文件里的幀去掉就行了?這樣不行的,通常會出現花屏。這需要重新把h.264文件輸入到解碼器,然后獲取到自己想要的幀,再輸入到一個新的編碼器中,生成你想要的H.264文件。在這里還有一個格式問題,並不是從解碼器解碼出來的數據,就能直接使用編碼器來編碼,有部分手機可以,有些會出現藍屏,甚至閃退的情況。這時候需要統一解碼器處理的格式。如果你使用這種形式獲取:
 
mMediaCodec.getOutputBuffer()
 
出來的格式各種各樣,你很難去兼容。google已經推出了一種新的格式:
 
mMediaCodec.getOutputImage(outIndex)
 
得出的是一個Image 對象,該對象可以保存為 JPEG格式圖片,也可以轉換成NV21(參考: http://www.cnblogs.com/welhzh/p/6079631.html),像上面拍攝部分,轉換成yuv422格式,再輸入到編碼器編碼。這樣不管什么機型都可以兼容了(我試用10多部不同廠商手機),雖然繞了很多彎路。
 
        在使用MediaCodec還是遇到比較多的問題,畢竟官網都說它是一個輕量的編解碼器封裝。該總結適合使用過MediaCodec或有一定的解碼編碼經驗的童鞋們。如果你還沒了解過 MediaCodec,可以參考官網:
 
     在使用MediaCodec的時候還遇到很多問題,這里沒有一一列舉出來, 歡迎有遇到同樣問題或類似問題的童鞋留言討論!

 
 


免責聲明!

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



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