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的時候還遇到不少問題,這裏沒有一一列舉出來, 歡迎有遇到一樣問題或相似問題的童鞋留言討論!
相關文章
相關標籤/搜索