請問android使用MediaCodec進行解碼,就是硬解碼嗎?軟解碼和硬解碼的優先順序是怎樣的?
在MediaCodec裡有介面可以列舉所有解碼格式,每種編碼可能都有多個解碼器。
MediaCodec mediaCodec = MediaCodec.createDecoderByType("video/avc");
我的應用裡面接收的是H264編碼資料,所以我選取的是video/avc,我們可以看一下MediaCodec.createDecoderByType()枚舉了哪些解編碼格式:
> /**
> * Instantiate a decoder supporting input data of the given mime type.
> *
> * The following is a partial list of defined mime types and their semantics:
> * <ul>
> * <li>"video/x-vnd.on2.vp8" - VP8 video (i.e. video in .webm)
> * <li>"video/x-vnd.on2.vp9" - VP9 video (i.e. video in .webm)
> * <li>"video/avc" - H.264/AVC video
> * <li>"video/mp4v-es" - MPEG4 video
> * <li>"video/3gpp" - H.263 video
> * <li>"audio/3gpp" - AMR narrowband audio
> * <li>"audio/amr-wb" - AMR wideband audio
> * <li>"audio/mpeg" - MPEG1/2 audio layer III
> * <li>"audio/mp4a-latm" - AAC audio (note, this is raw AAC packets, not packaged in LATM!)
> * <li>"audio/vorbis" - vorbis audio
> * <li>"audio/g711-alaw" - G.711 alaw audio
> * <li>"audio/g711-mlaw" - G.711 ulaw audio
> * </ul>
> *
> * @param type The mime type of the input data.
> */
> public static MediaCodec createDecoderByType(String type) {
> return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
> }
可以看到我選的”video/avc” - H.264/AVC video是一種H264的解碼方式,但並不能證明我使用的就一定是硬解碼
我們先來看一下Android系統中解碼器的命名,軟解碼器通常是以OMX.google開頭的。硬解碼器通常是以OMX.[hardware_vendor]開頭的,比如TI的解碼器是以OMX.TI開頭的。當然還有一些不遵守這個命名規範的,不以OMX.開頭的,那也會被認為是軟解碼器。
判斷規則見frameworks/av/media/libstagefright/OMXCodec.cpp:
static bool IsSoftwareCodec(const char *componentName) {
if (!strncmp("OMX.google.", componentName, 11)) {
return true;
}
if (!strncmp("OMX.", componentName, 4)) {
return false;
}
return true;
}
其實MediaCodec呼叫的是在系統中註冊的解碼器,系統中存在的解碼器可以很多,但能夠被應用使用的解碼器是根據配置來的,即/system/etc/media_codecc.xml。這個檔案一般由硬體或者系統的生產廠家在build整個系統的時候提供,一般是儲存在程式碼的device/[company]/[codename]目錄下的,例如device/samsung/tuna/media_codecs.xml。這個檔案配置了系統中有哪些可用的codec以及,這些codec對應的媒體檔案型別。在這個檔案裡面,系統裡面提供的軟硬codec都需要被列出來。
也就是說,如果系統裡面實際上包含了某個codec,但是並沒有被配置在這個檔案裡,那麼應用程式也無法使用到。
在這個配置檔案裡面,如果出現多個codec對應同樣型別的媒體格式的時候,這些codec都會被保留起來。當系統使用的時候,將會選擇第一個匹配的codec。除非是指明瞭要軟解碼還是硬解碼,但是Android的framework層為上層提供服務的AwesomePlayer中在處理音訊和視訊的時候,對到底是選擇軟解還是硬解的引數沒有設定。所以雖然底層是支援選擇的,但是對於上層使用MediaPlayer的Java程式來說,還是隻能接受預設的codec選取規則。
但是Android提供的命令列程式/system/bin/stagefright在播放音訊檔案的時候,倒是可以根據引數來選擇到底使用軟解碼還是硬解碼,但是該工具只支援播放音訊,不支援播放視訊。
一般來說,如果系統裡面有對應的媒體硬體解碼器的話,系統開發人員應該是會配置在media_codecs.xml中,所以大多數情況下,如果有硬體解碼器,那麼我們總是會使用到硬體解碼器。極少數情況下,硬體解碼器存在,但不配置,我猜只可能是這個硬解碼器還有bug,暫時還不適合釋出,所以不用使用。