使得內存的使用更為合理,限制每個應用的可用內存上限,可以防止某些應用程式惡意或者無意使用過多的內存,而導致其他應用無法正常運行,我們眾所周知的Android是有多進程的,如果一個進程(也就是一個應用)耗費過多的內存,其他的應用還搞毛呢?當然在這裏其實是有一個例外,那就是如果你的應用使用了很多本地代碼,在本地代碼中創建對象解碼圖像是不會被計算到的,這是因為你使用本地方法創建的對象或者解碼的圖像使用的是本地堆的內存,跟系統是平級的,而我們通過Framework調用BitmapFactory.decodeFile()方法解碼時,系統雖然也是調用本地代碼來進行解碼的,但是Android Framework在實現的時候,刻意地將這部分解碼使用的內存從堆裏面分配了而不是從本地堆裏分配的內存,所以才會出現OOM,當然並不是說從本地堆裏分配就不會出現OOM,本地堆分配內存超過系統可用內存限制的話,通常都是直接崩潰,什麼錯誤可能都看不到,也許會有一些崩潰的錯誤字節碼之類的。
省電的考慮,呃...,原因我好像也不能很明白地說出來。

 

回到正題來,我們在應用的設計和開發中可能會經常碰到需要在一個介面上顯示數十張圖片乃至上百張,當然限於手機螢幕的大小我們通常在設計中會使用類似於清單或者網格的控制項來展示,也就是說通常一次需要顯示出來圖片數還是一個相對確定的數字,通常也不會太大。如果數目比較大的畫,通常顯示的控制項自身尺寸就會比較小,這個時候可以採用縮略圖策略。下面我們來看看如果避免出現OOM的錯誤,這個解決方案參考了Android示範程式XML Adapters中的ImageDownloader.java中的實現,主要是使用了一個二級緩存類似的機制,就是有一個數據結構中直接持有解碼成功的Bitmap對象引用,同時使用一個二級緩存數據結構持有解碼成功的Bitmap對象的SoftReference對象,由於SoftReference對象的特殊性,系統會在需要內存的時候首先將SoftReference對象持有的對象釋放掉,也就是說當VM發現可用內存比較少了需要觸發GC的時候,就會優先將二級緩存中的Bitmap回收,而保有一級緩存中的Bitmap對象用於顯示。

 

其實這個解決方案最為關鍵的一點是使用了一個比較合適的數據結構,那就是LinkedHashMap類型來進行一級緩存Bitmap的容器,由於LinkedHashMap的特殊性,我們可以控制其內部存儲對象的個數並且將不再使用的對象從容器中移除,這就給二級緩存提供了可能性,我們可以在一級緩存中一直保存最近被訪問到的Bitmap對象,而已經被訪問過的圖片在LinkedHashMap的容量超過我們預設值時將會把容器中存在時間最長的對象移除,這個時候我們可以將被移除出LinkedHashMap中的對象存放至二級緩存容器中,而二級緩存中對象的管理就交給系統來做了,當系統需要GC時就會首先回收二級緩存容器中的Bitmap對象了。在獲取對象的時候先從一級緩存容器中查找,如果有對應對象並可用直接返回,如果沒有的話從二級緩存中查找對應的SoftReference對象,判斷SoftReference對象持有的Bitmap是否可用,可用直接返回,否則返回空。

 

主要的代碼段如下:


 

戮克 發表在 痞客邦 留言(0) 人氣()

root@t225 libexec]# perl -MMIME::Base64 -e 'print encode_base64("123")'
MTIz
[root@t225 libexec]# perl -MMIME::Base64 -e 'print decode_base64("MTIz")'
123
[root@t225 libexec]#

戮克 發表在 痞客邦 留言(0) 人氣()

H264解碼器源碼,移植ffmpeg中的H264解碼部分到Android,深度刪減優化,在模擬器(320x480)中驗證通過。
 
  程式的採用jni架構。介面部分,檔讀取,視頻顯示都是用java做的,底層的視頻解碼用C來做滿足速度的要求。
 
  在這個版本中,從H264碼流中分割出Nal是在java層做的,這樣在java層直接調用解碼時就知道是否有顯示視頻,缺點的就是耦合度/封裝性差一點。
 
  如果採用在底層做Nal分割的方法,可以封裝得好看一些,但是每次送的資料有限制,如果送的資料太多,底層可能會一次解碼出好幾幀視頻,但是通知到介面層只能顯示一幀,造成丟幀的現象。 如果每次送的資料較少,就會有很多次底層調用沒有進行實質解碼,很小氣的做法,比如有一壓縮資料幀需要600位元組,如果一次送100個位元組給解碼器,那麼要送6次才會進行實質解碼,因為每個資料幀有大有小,所以只能取極小值才不會導致丟幀。
 
  不過所有的編碼解碼都是各種因素平衡折中的結果,具體用什麼方法具體分析。
 
  為便於支援不同解析度的碼流,修改了代碼。現在只需要修改H264Android.java檔中第51,74,75行就可測試新解析度。
 
  有些大分辨率的碼流可能會異常,優先修改H264Android.java檔中第161行把Nal緩衝區改大。
 
  兩版本都是用 android-ndk-1.6_r1-windows.zip 和 cygwin 1.7.5-1, gcc4 4.3.4-3 (用 cygcheck -c查看) 編譯。
 
  注意 /jni/H264Android.cpp檔添加了extern "C" 關鍵聲明。
 
  解碼源碼下載位址:http://files.cnblogs.com/mcodec/H264Android.7z

戮克 發表在 痞客邦 留言(0) 人氣()

Const sBASE_64_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

Function Base64decode(ByVal asContents)
Dim lsResult
Dim lnPosition
Dim lsGroup64, lsGroupBinary
Dim Char1, Char2, Char3, Char4
Dim Byte1, Byte2, Byte3
If Len(asContents) Mod 4 > 0 Then asContents = asContents & String(4 - (Len(asContents) Mod 4), " ")
lsResult = ""

For lnPosition = 1 To Len(asContents) Step 4

戮克 發表在 痞客邦 留言(0) 人氣()

一般情況下Android的平臺都是硬解碼視頻的,尤其是在Arm平臺這種成熟的硬體平臺上面(硬解碼代碼由晶片廠商提供)。但是Android移植到MIPS平臺時間還不長,還不成熟,還需要自己實現硬體解碼的工作。為了早日讓Android在MIPS平臺運行起來,我選擇了先用軟解碼播放視頻。

 

我的Android代碼是從Android on MIPS社區獲得的代碼。發現軟解碼視頻播放過程中會發生崩潰。經過分析好像是記憶體分配的問題。

 

經過研究OpenCore庫(Android框架是通過OpenCore來播放視頻的,網上有很多關於OpenCore的介紹,這裡就不多說了),並參考Android平臺——Surfaceflinger機制。發現問題出在原始檔案:

 

frameworks/base/libs/surfaceflinger/LayerBuffer.cpp的LayerBuffer::BufferSource::postBuffer方法中:

 

............
buffer = new LayerBuffer::Buffer(buffers, offset);

戮克 發表在 痞客邦 留言(0) 人氣()

一般情況下Android的平臺都是硬解碼視頻的,尤其是在Arm平臺這種成熟的硬體平臺上面(硬解碼代碼由晶片廠商提供)。但是Android移植到MIPS平臺時間還不長,還不成熟,還需要自己實現硬體解碼的工作。為了早日讓Android在MIPS平臺運行起來,我選擇了先用軟解碼播放視頻。

 

我的Android代碼是從Android on MIPS社區獲得的代碼。發現軟解碼視頻播放過程中會發生崩潰。經過分析好像是記憶體分配的問題。

 

經過研究OpenCore庫(Android框架是通過OpenCore來播放視頻的,網上有很多關於OpenCore的介紹,這裡就不多說了),並參考Android平臺——Surfaceflinger機制。發現問題出在原始檔案:

 

frameworks/base/libs/surfaceflinger/LayerBuffer.cpp的LayerBuffer::BufferSource::postBuffer方法中:

 

............
buffer = new LayerBuffer::Buffer(buffers, offset);

戮克 發表在 痞客邦 留言(0) 人氣()